diff options
Diffstat (limited to 'extras/path_id/path_id.sh')
-rwxr-xr-x | extras/path_id/path_id.sh | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/extras/path_id/path_id.sh b/extras/path_id/path_id.sh new file mode 100755 index 0000000000..7b4973fa03 --- /dev/null +++ b/extras/path_id/path_id.sh @@ -0,0 +1,601 @@ +#!/bin/sh + +# provide the shortest possible unique hardware path to a device +# for the Linux Persistent Device Naming scheme +# +# Copyright (C) 2005-2006 SUSE Linux Products GmbH +# Author: +# Hannes Reinecke <hare@suse.de> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation version 2 of the License. + +SYSFS=/sys +RESULT=1 +TYPE= +OPWD="`pwd`" +full_sysfs_path= +full_sysfs_device_path= + +if [ -z "$DEVPATH" -a -z "$1" ] ; then + exit 1 +fi + +if [ -z "$DEVPATH" ] ; then + case "$1" in + $SYSFS/*) + DEVPATH="${1#$SYSFS}" + ;; + *) + DEVPATH=$1 + ;; + esac +fi + +if [ ! -e $SYSFS$DEVPATH/dev ] ; then + exit 1 +fi + +case "$DEVPATH" in + /devices/*) + cd "$SYSFS$DEVPATH/subsystem"; + TYPE="`pwd -P`" + cd "$OPWD" + TYPE="${TYPE##*/}" + ;; + /class/*) + TYPE="${DEVPATH#/class/}" + TYPE="${TYPE%%/*}" + ;; + /block/*) + TYPE=block + ;; + *) + exit 1 + ;; +esac + +get_port_offset () { + local type offset port + type=$1 + offset=$2 + for i in $type[0-9]* ; do + : i $i + port="${i#$type}" + if [ "$port" -lt "$offset" ] ; then offset=$port ; fi + done + echo $offset +} + +handle_pci () { + local DEV=$1 + cd -P $1 + DEV=${PWD} + pci_id=${DEV##*/} + host_dev_path=$DEV + + # cciss devices don't have a separate sysfs node + for blk_link in block*; do + if [ -L "$blk_link" ]; then + case "$blk_link" in + *cciss*) + d=cciss-${blk_link#*cciss\!} + ;; + esac + fi + done + while [ ! -z "$host_dev_path" ] ; do + case "$host_dev_path" in + */pci[0-9]*) + host_dev_path=${host_dev_path%/*} + ;; + *) + break + ;; + esac + done + if [ "$d" ]; then + d="pci-$pci_id-$d" + else + d="pci-$pci_id" + fi + D="$host_dev_path" + RESULT=0 +} + +handle_platform () { + local DEV=$1 + cd -P $1 + DEV=${PWD} + platform_id=${DEV##*/} + host_dev_path=$DEV + while [ ! -z "$host_dev_path" ] ; do + case "$host_dev_path" in + */platform*) + host_dev_path=${host_dev_path%/*} + ;; + *) + break + ;; + esac + done + if [ "$d" ]; then + d="platform-$platform_id-$d" + else + d="platform-$platform_id" + fi + D="$host_dev_path" + RESULT=0 +} + +handle_xen () { + local DEV=$1 + cd -P $1 + vbd_id=${DEV##*/} + host_dev_path=$DEV + while [ ! -z "$host_dev_path" ] ; do + case "$host_dev_path" in + */vbd*) + host_dev_path=${host_dev_path%/*} + ;; + *) + break + ;; + esac + done + if [ "$d" ]; then + d="xen-$vbd_id-$d" + else + d="xen-$vbd_id" + fi + D="$host_dev_path" + RESULT=0 +} + +handle_serio () { + local DEV=$1 + cd -P $1 + DEV=${PWD} + serio_id=${DEV##*/serio} + host_dev_path=$DEV + while [ ! -z "$host_dev_path" ] ; do + case "$host_dev_path" in + */serio*) + host_dev_path=${host_dev_path%/*} + ;; + *) + break + ;; + esac + done + if [ "$d" ]; then + d="serio-$serio_id-$d" + else + d="serio-$serio_id" + fi + D="$host_dev_path" + RESULT=0 +} + +handle_ide () { + : handle_ide $* + local DEV=$1 + local port idedev idecontroller + # IDE + : DEV $DEV + port=${DEV##*/} + idedev=${DEV%/*} + idecontroller=${idedev%/*} + # port info if the controller has more than one interface + port="${port#ide}" + : port $port d $d + : idedev $idedev kernel_port $port + case "${port#*.}" in + 0) + channel=0 + ;; + 1) + channel=1 + ;; + *) + echo "Error: $idedev is neither master or slave" >&2 + ;; + esac + cd $idecontroller + offset="`get_port_offset ide ${port%.*}`" + cd "$OPWD" + : port offset $offset + port=$((${port%.*} - $offset)) + if [ "$d" ] ; then + d="ide-${port}:$channel-$d" + else + d="ide-${port}:$channel" + fi + D=$idecontroller + RESULT=0 +} + +handle_scsi () { + : handle_scsi $* + local DEV=$1 + local cil controller_port controller_dev + # SCSI device + cil="${DEV##*/}" + cil="${cil#*:}" + target_dev=${DEV%/*} + target_id=${target_dev##*/target} + cd "$target_dev" + target_num=0 + for tid in ${target_id}* ; do + target_num=$(( $target_num + 1 )) + done + controller_port=${target_dev%/*} + controller_dev="${controller_port%/*}" + : controller_dev $controller_dev + : controller_port $controller_port + # a host controller may have more than one interface/port + controller_port="${controller_port##*/host}" + # + cd "$controller_dev" + controller_offset=$(get_port_offset host $controller_port) + cd "$OPWD" + controller_port=$(( $controller_port - $controller_offset)) + scsi_id="scsi-${controller_port}:${cil}" + if [ "$d" ] ; then + d="${scsi_id}-$d" + else + d="$scsi_id" + fi + D="$controller_dev" + RESULT=0 +} + +handle_firewire () { + : handle_firewire $* + local DEV=$1 + if [ -f "$D/ieee1394_id" ] ; then + read ieee1394_id < $D/ieee1394_id + fi + if [ -z "$ieee1394_id" ] ; then + : no IEEE1394 ID + RESULT=1 + return + fi + fw_host_dev=${DEV%/fw-host*} + # IEEE1394 devices are always endpoints + d="ieee1394-0x$ieee1394_id" + D="$fw_host_dev" + RESULT=0 +} + +handle_fc () { + : handle_fc $* + local DEV=$1 + local cil controller_port controller_dev + # SCSI-FC device + fc_tgt_hcil="${DEV##*/}" + fc_tgt_lun="${fc_tgt_hcil##*:}" + fc_tgt_path="${DEV%/*}" + fc_tgt_num="${fc_tgt_path##*/}" + fc_tgt_dev="${fc_tgt_path}/fc_transport/${fc_tgt_num}" + if [ -e "$fc_tgt_dev/port_name" ]; then + read wwpn < $fc_tgt_dev/port_name + fi + if [ -z "$wwpn" ] ; then + : no WWPN + D= + RESULT=1 + return + fi + # Linux currently knows about 32bit luns + tmp_lun3=$(printf "%04x" $(($fc_tgt_lun & 0xFFFF))) + tmp_lun2=$(printf "%04x" $(( ($fc_tgt_lun >> 16) & 0xFFFF))) + tmp_lun1="0000" + tmp_lun0="0000" + if (($fc_tgt_lun == 0)) ; then + lun="0x0000000000000000" + else + lun="0x${tmp_lun3}${tmp_lun2}${tmp_lun1}${tmp_lun0}" + fi + controller_dev="${fc_tgt_path%/host[0-9]*}" + # FC devices are always endpoints + d="fc-${wwpn}:${lun}" + D="$controller_dev" + RESULT=0 +} + +handle_sas () { + : handle_sas $* + local DEV=$1 + local cil adapter controller_dev + local lun + lun=${DEV##*:} + # SAS device + sas_end_path="${DEV%%/target*}" + sas_host_path="${sas_end_path%%/port*}" + sas_phy_path="${sas_end_path#*/host*/}" + sas_phy_path="${sas_phy_path%%/*}" + sas_phy_path="${sas_host_path}/${sas_phy_path}" + + sas_phy_id=255 + for phy in $sas_phy_path/phy-*/sas_phy/phy-* ; do + if [ -d "$phy" ] ; then + read phy_id < $phy/phy_identifier + if [ $phy_id -lt $sas_phy_id ]; then + sas_phy_id=$phy_id + fi + fi + done + + if [ $sas_phy_id -eq 255 ] ; then + : no initiator address + D= + RESULT=1 + return + fi + + sas_port_id="${sas_phy_path##*/port-}" + sas_port_dev="/sys/class/sas_port/port-${sas_port_id}" + if [ -e "$sas_port_dev/num_phys" ] ; then + read phy_port < $sas_port_dev/num_phys + fi + + sas_end_id="${sas_end_path##*end_device-}" + sas_end_dev="/sys/class/sas_device/end_device-${sas_end_id}" + if [ -e "$sas_end_dev/sas_address" ]; then + read end_address < $sas_end_dev/sas_address + read end_id < $sas_end_dev/phy_identifier + fi + if [ -z "$end_address" ] ; then + : no end device address + D= + RESULT=1 + return + fi + sas_end_address="$end_address:$end_id" + controller_dev="${sas_host_path%/host[0-9]*}" + # SAS devices are always endpoints + d="sas-phy${sas_phy_id}:${phy_port}-${sas_end_address}-lun$lun" + D="$controller_dev" + RESULT=0 +} + +handle_iscsi() { + local DEV=$1 + local iscsi_session_dir + local iscsi_session iscsi_session_path + local iscsi_connection iscsi_connection_path + local iscsi_scsi_lun + # iSCSI device + iscsi_session_dir="${DEV%%/target*}" + iscsi_session="${iscsi_session_dir##*/}" + iscsi_session_path=/sys/class/iscsi_session/${iscsi_session} + if [ ! -d "$iscsi_session_path" ] ; then + : no iSCSI session path + RESULT=1 + return + fi + # Currently we're not doing MC/S + for conn in ${iscsi_session_dir}/connection* ; do + iscsi_conn_num=${conn##*:} + if [ "$iscsi_conn_num" = '0' ] ; then + iscsi_connection=$(basename $conn) + fi + done + if [ -z "$iscsi_connection" ] ; then + : no iSCSI connection found + RESULT=1 + return + fi + iscsi_connection_path=/sys/class/iscsi_connection/${iscsi_connection} + if [ ! -d "$iscsi_connection_path" ] ; then + : no iSCSI connection path + RESULT=1 + return + fi + if [ -e "${iscsi_session_path}/targetname" ]; then + read iscsi_tgtname < ${iscsi_session_path}/targetname + fi + if [ -z "$iscsi_tgtname" ] ; then + : No iSCSI Targetname + RESULT=1 + return + fi + if [ -e "${iscsi_connection_path}/persistent_address" ] ; then + read iscsi_address < ${iscsi_connection_path}/persistent_address + fi + if [ -z "$iscsi_address" ] ; then + : No iSCSI Target address + RESULT=1 + return + fi + if [ -e "${iscsi_connection_path}/persistent_port" ] ; then + read iscsi_port < ${iscsi_connection_path}/persistent_port + fi + iscsi_scsi_lun="${DEV##*:}" + d="ip-${iscsi_address}:${iscsi_port}-iscsi-${iscsi_tgtname}-lun-${iscsi_scsi_lun}" + RESULT=0 +} + +handle_usb () { +: handle_usb $* + local DEV=$1 + cd -P $1 + DEV=${PWD} + port_id=${DEV##*/} + port_num=${port_id#*-} + host_dev_path=$DEV + while [ ! -z "$host_dev_path" ] ; do + case "$host_dev_path" in + */usb*) + usb_host_path=$host_dev_path + host_dev_path="${host_dev_path%/*}" + ;; + *) + break + ;; + esac + done + : host_dev_path $host_dev_path + usb_host_num=${usb_host_path##*/usb} + + cd "$host_dev_path" + usb_host_offset=$(get_port_offset usb $usb_host_num) + usb_host_port=$(($usb_host_num - $usb_host_offset)) + cd "$OPWD" + if [ "$d" ] ; then + d="usb-$usb_host_port:$port_num-${d}" + else + d="usb-$usb_host_port:$port_num" + fi + D="$host_dev_path" + RESULT=0 +} + +handle_device () { + full_sysfs_path="$SYSFS$DEVPATH" + case "$DEVPATH" in + /devices/*) + full_sysfs_path="${full_sysfs_path%/*}" + # skip parent device of the same subsystem + if [ -L $full_sysfs_path/subsystem ]; then + cd "$full_sysfs_path/subsystem"; + subsys="`pwd -P`" + cd "$OPWD" + subsys="${subsys##*/}" + if [ "$subsys" = "$TYPE" ]; then + : skip same subsystem parent + full_sysfs_path="${full_sysfs_path%/*}" + fi + fi + # skip subsystem directory + subsys="${full_sysfs_path##*/}" + if [ "$subsys" = "$TYPE" ]; then + : skip subsystem directory + full_sysfs_path="${full_sysfs_path%/*}" + fi + cd $full_sysfs_path + ;; + *) + # old sysfs layout + if [ ! -L $full_sysfs_path/device ]; then + full_sysfs_path="${full_sysfs_path%/*}" + : full_sysfs_path "$full_sysfs_path" + if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ]; then + return + fi + fi + if [ -L $full_sysfs_path/device/device ]; then + cd $full_sysfs_path/device/device + else + cd $full_sysfs_path/device + fi + ;; + esac + full_sysfs_device_path="`pwd -P`" + cd "$OPWD" + + D=$full_sysfs_device_path + while [ ! -z "$D" ] ; do + case "$D" in + */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*) + handle_ide "$D" + ;; + */css0/*) + if [ -r $full_sysfs_device_path/wwpn ]; then + read wwpn < $full_sysfs_device_path/wwpn + fi + if [ -r $full_sysfs_device_path/fcp_lun ]; then + read lun < $full_sysfs_device_path/fcp_lun + fi + if [ -r $full_sysfs_device_path/hba_id ]; then + read bus_id < $full_sysfs_device_path/hba_id + fi + if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then + # S/390 zfcp adapter + d="ccw-$bus_id-zfcp-$wwpn:$lun" + RESULT=0 + else + # DASD devices + bus="ccw" + adapter=${D##*/} + d="$bus-$adapter" + RESULT=0 + fi + D= + ;; + */rport-[0-9]*:[0-9]*-[0-9]*/*) + handle_fc "$D" + ;; + */end_device-[0-9]*:[0-9]*:[0-9]*/*) + handle_sas "$D" + ;; + */fw-host[0-9]*/*) + handle_firewire "$D" + ;; + */session[0-9]*/*) + handle_iscsi "$D" + D= + ;; + */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*) + handle_scsi "$D" + ;; + */ttyUSB*) + D=${D%/ttyUSB*} + ;; + */usb[0-9]*/[0-9]*/*) + handle_usb "$D" + ;; + */pci[0-9]*:[0-9]*) + handle_pci "$D" + ;; + */serio[0-9]*) + handle_serio "$D" + ;; + */platform/*) + handle_platform "$D" + ;; + */vbd-[0-9]*) + handle_xen "$D" + ;; + */devices) + D= + ;; + *) + : not handled + RESULT=1 + return + ;; + esac + done + if [ "$TYPE" = "scsi_tape" ] ; then + devname=${full_sysfs_path##*/} + rewind="${devname%%st*}" + mode="${devname##*st}" + case "$mode" in + *l) + mode="l" + ;; + *m) + mode="m" + ;; + *a) + mode="a" + ;; + *) + mode="" + ;; + esac + if [ "$d" ]; then + d="$d-${rewind}st${mode}" + fi + fi +} + +handle_device +if [ -z "$d" ]; then + exit 1 +fi +echo "ID_PATH=$d" +exit 0 |