#!/bin/sh
-# provide the shortest possible unique hardware path to a block device
-# for the udev persistent disk device naming scheme
+# provide the shortest possible unique hardware path to a device
+# for the Linux Persistent Device Naming scheme
#
-# Copyright (C) 2005 SUSE Linux Products GmbH
+# Copyright (C) 2005-2006 SUSE Linux Products GmbH
# Author:
# Hannes Reinecke <hare@suse.de>
#
# Free Software Foundation version 2 of the License.
#
# to be called from a udev rule to return the name for a symlink
-# DEVPATH=/block/sda/sda3 path_id
+# DEVPATH=<devpath>; path_id
# path_id <devpath>
-# example for all block devices on a system:
-# for i in `find /sys/block -name dev` ;do DEVPATH="`echo $i | sed -e 's@^/sys\|/dev@@g'`" path_id ; done
-
-# examples:
-# SCSI cdrom
-# /block/sr0 -> /devices/pci0002:30/0002:30:0c.0/host0/0:0:1:0
-# result: pci-0002:30:0c.0-scsi-0:0:1:0
-# SCSI disk
-# /block/sda -> /devices/pci0002:30/0002:30:0c.0/host0/0:0:4:0
-# result: pci-0002:30:0c.0-scsi-0:0:4:0
-# SATA disk, 4 channels per controller
-# /block/sda -> /devices/pci0001:00/0001:00:07.0/0001:05:0c.0/host0/0:0:0:0
-# result: pci-0001:05:0c.0-scsi-0:0:0:0
-# IDE disk
-# /block/hda -> /devices/pci0002:02/0002:02:0d.0/ide0/0.0
-# result: pci-0002:02:0d.0-ide-0.0
-# IDE cdrom on a Mac ASIC:
-# /block/hdc -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.00020000:ata-3/ide1/1.0
-# result: mac-io_ata-3_master
-# IDE cdrom on a Mac ASIC, with ide-scsi:
-# /block/sr0 -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.0001f000:ata-4/ide0/0.1/host2/2:0:0:0
-# result: mac-io_ata-4_slave
-
-# USB CDrom drive without 'serial' number:
-# reusing 'product' and 'manufacturer' string, if available
-# /block/sr0 -> /devices/pci0001:00/0001:00:04.0/0001:02:0b.0/usb4/4-2/4-2:1.0/host4/4:0:0:0
-# result: usb-storage-odd-Freecom-USIDERev930:0:0:0
-
-# devices may have several interfaces on one PCI device, like IDE:
-# pci-0001:00:04.0_ide1-master
-# pci-0001:00:04.0_ide2-master
-# pci-0001:00:04.0_ide2-slave
-# they are marked as ports, it is expected that the driver shows
-# ide1 even if there is nothing connected to either master or slave
-# interface
-#
-# match order is important.
-# first IDE to find ide-scsi devices.
-# then SCSI
-# first usb-storage
-# then firewire sbp2
-# then the rest
+# examples for all block devices on a system:
+# for i in `find /sys/class/block`; do DEVPATH="`echo $i | sed -e 's@^/sys\|/dev@@g'`"; path_id; done
SYSFS=/sys
RESULT=1
-CDROM=
TYPE=
OPWD="`pwd`"
-# Check for 'pwd -P'
-if $(pwd -P > /dev/null 2>&1); then
- pwd_cmd="pwd -P"
-else
- pwd_cmd="pwd"
-fi
-full_sysfs_class_path=
+full_sysfs_path=
full_sysfs_device_path=
if [ -z "$DEVPATH" -a -z "$1" ] ; then
- exit 1
+ exit 1
fi
if [ -z "$DEVPATH" ] ; then
- case "$1" in
- $SYSFS/*)
- DEVPATH="${1#$SYSFS}"
- ;;
- *)
- DEVPATH=$1
- ;;
- esac
+ case "$1" in
+ $SYSFS/*)
+ DEVPATH="${1#$SYSFS}"
+ ;;
+ *)
+ DEVPATH=$1
+ ;;
+ esac
fi
-if [ ! -d $SYSFS$DEVPATH ] ; then
- exit 1
-fi
-if [ ! -f $SYSFS$DEVPATH/dev ] ; then
- exit 1
+if [ ! -e $SYSFS$DEVPATH/dev ] ; then
+ exit 1
fi
case "$DEVPATH" in
- /block/*)
- TYPE=block
- ;;
- /class/*)
- TYPE="${DEVPATH#/class/}"
- TYPE="${TYPE%%/*}"
- ;;
- *)
- exit 1
- ;;
+ /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 () {
- 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
- if [ "$port" != "0" ] ; then
- echo $(($2 - $offset))
- fi
+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_block_ide () {
-: handle_block_ide $*
+handle_pci () {
local DEV=$1
- local port idedev idecontroller
- # IDE
- : DEV $DEV
- d=$DEV
- case "$DEV" in
- # remove ide-scsi part, leave only channel info
- */ide[0-9]*/host[0-9]*)
- while [ ! -z "$d" ] ; do
- case "$d" in
- */host[0-9]*)
- d="${d%/*}"
- continue
+ cd -P $1
+ DEV=${PWD}
+ pci_id=${DEV##*/}
+ host_dev_path=$DEV
+ while [ ! -z "$host_dev_path" ] ; do
+ case "$host_dev_path" in
+ */pci[0-9]*)
+ host_dev_path=${host_dev_path%/*}
;;
- *)
+ *)
break
;;
- esac
- done
- ;;
- esac
- idedev=$d
- while [ ! -z "$d" ] ; do
- case "$d" in
- */ide[0-9]*)
- port="${d##*/}"
- d="${d%/*}"
- continue
- ;;
- *)
- break
- ;;
esac
done
- idecontroller=$d
+ d="pci-$pci_id-$d"
+ 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 "${idedev##*.}" in
- 0)
- channel=0
- ;;
- 1)
- channel=1
- ;;
- *)
- echo "Error: $idedev is neither master or slave" >&2
- esac
- case "$d" in
- *:mac-io/*)
- : mac-io: $d
- d="`echo $d | sed -e 's@^.*:mac-io[^:]\+:\([^/]\+\).*@mac-io_\1@'`"
- ;;
- /sys/devices)
- # PCMCIA devices
- ifname=${full_sysfs_class_path##*/}
- set -- `sed -n "/$ifname/p" /var/lib/pcmcia/stab`
- d="pcmcia-$1"
- ;;
+ case "${port#*.}" in
+ 0)
+ channel=0
+ ;;
+ 1)
+ channel=1
+ ;;
*)
- d="pci-${d##*/}"
- # d="`echo $d | sed -e 's@^.*/\([^/]\{1,\}\)/.@pci-\1@'`"
- ;;
+ echo "Error: $idedev is neither master or slave" >&2
+ ;;
esac
-
cd $idecontroller
- port="`get_port ide $port`"
+ offset="`get_port_offset ide ${port%.*}`"
cd "$OPWD"
- : hardware_port $port
- if [ -z "$port" ] ; then
- d="${d}-ide-0:$channel"
+ : port offset $offset
+ port=$((${port%.*} - $offset))
+ if [ "$d" ] ; then
+ d="ide-${port}:$channel-$d"
else
- d="${d}-ide-${port}:$channel"
+ d="ide-${port}:$channel"
fi
-
+ D=$idecontroller
RESULT=0
}
-handle_block_scsi () {
-: handle_block_scsi $*
+handle_scsi () {
+ : handle_scsi $*
local DEV=$1
local cil controller_port controller_dev
# SCSI device
cil="${DEV##*/}"
cil="${cil#*:}"
- controller_dev=$DEV
- while [ ! -z "$controller_dev" ] ; do
- case "$controller_dev" in
- */host[0-9]*)
- controller_port=$controller_dev
- controller_dev="${controller_dev%/*}"
- ;;
- *) break ;;
- esac
+ 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##*/}"
- controller_port="${controller_port##host}"
+ controller_port="${controller_port##*/host}"
#
- case "$controller_dev" in
- # grand central, old powermacs
- *:gc/*)
- adapter="`echo $controller_dev | sed -e 's@/[^/]\{1,\}$@@;s@^.*/@@;s@^.*:@@'`"
- bus="gc"
- ;;
- # PARISC devices
- *parisc*)
- adapter="${controler_dev##*/}"
- bus=parisc;
- ;;
- *)
- adapter="${controller_dev##*/}"
- bus="pci"
- ;;
- esac
cd "$controller_dev"
- controller_port="`get_port host $controller_port`"
+ controller_offset=$(get_port_offset host $controller_port)
cd "$OPWD"
- d="$bus-$adapter"
- if [ -z "$controller_port" ] ; then
- controller_port=0
+ 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="${d}-scsi-${controller_port}:${cil}"
+ D="$controller_dev"
RESULT=0
}
-handle_block_usb_storage () {
-: handle_block_usb_storage $*
+handle_firewire () {
+ :handle_firewire $*
local DEV=$1
- cil="${DEV##*/}"
- cil="${cil#*:}"
- controller_dev=$DEV
- while [ ! -z "$controller_dev" ] ; do
- case "$controller_dev" in
- */host[0-9]*)
- controller_dev="${controller_dev%/*}"
- ;;
- *) break ;;
- esac
- done
- : controller_dev $controller_dev
- #
- # usb-storage devs have a serial number, hopefully unique
- serial=
- if [ -f $controller_dev/../serial ] ; then
- serial="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../serial`"
- : serial XXX_${serial}_XXX
- d="usb-$serial"
- serial="`echo $serial | sed -e 's@[ 0]\{1,\}@@g'`"
+ if [ -f "$D/ieee1394_id" ] ; then
+ read ieee1394_id < $D/ieee1394_id
fi
- if [ -z "$serial" ] ; then
- # no serial, broken device
- # has eventually binary junk in vpd
- identifier=
- if [ -f $controller_dev/../product ] ; then
- product="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../product`"
- fi
- if [ -f $controller_dev/../manufacturer ] ; then
- manufacturer="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../manufacturer`"
- fi
- if [ -z "$product" -o -z "$manufacturer" ] ; then
- read idvendor < $controller_dev/../idVendor
- read idproduct < $controller_dev/../idProduct
- identifier="0x${idvendor}-0x${idproduct}"
- else
- identifier="${manufacturer}-${product}"
- fi
- d="usb-${identifier}"
+ if [ -z "$ieee1394_id" ] ; then
+ : no IEEE1394 ID
+ RESULT=1
+ return
fi
- d="$d:$cil"
+ 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
+ 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_block () {
- full_sysfs_class_path="$SYSFS$DEVPATH"
- if [ ! -f $full_sysfs_class_path/dev ] ; then return ; fi
- # the main device has (hopefully) a symlink to the real device
- # a partition is a subdir of the main (raw) device
- if [ ! -L $full_sysfs_class_path/device ] ; then
- if [ -f $full_sysfs_class_path/range ] ; then return ; fi
- full_sysfs_class_path="${full_sysfs_class_path%/*}"
- : full_sysfs_class_path "$full_sysfs_class_path"
- if [ ! -L $full_sysfs_class_path/device -o ! -f $full_sysfs_class_path/dev ] ; then
- return
+handle_sas () {
+ : handle_sas $*
+ local DEV=$1
+ local cil adapter controller_dev
+ # SAS device
+ sas_host_path="${DEV%%/phy*}"
+ sas_phy_path="${DEV#*/host*/}"
+ sas_phy_path="${sas_phy_path%%/target*}"
+ sas_phy_id="${sas_phy_path%%/*}"
+ sas_rphy_id="${sas_phy_path##*/}"
+ sas_phy_dev="${sas_host_path}/${sas_phy_id}/sas_phy:${sas_phy_id}"
+ if [ -e "$sas_phy_dev/sas_address" ]; then
+ read phy_address < $sas_phy_dev/sas_address
+ read phy_port < $sas_phy_dev/port_identifier
+ read phy_id < $sas_phy_dev/phy_identifier
fi
- fi
- cd $full_sysfs_class_path/device
- full_sysfs_device_path="`$pwd_cmd`"
- cd "$OPWD"
- D=$full_sysfs_device_path
- case "$D" in
- */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
- handle_block_ide "$D"
- ;;
- */usb[0-9]*/[0-9]*/host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
- handle_block_usb_storage "$D"
- ;;
- */css0/*)
- if [ -r $full_sysfs_device_path/wwpn ]; then
- read wwpn < $full_sysfs_device_path/wwpn
+ if [ -z "$phy_address" ] ; then
+ : no initiator address
+ RESULT=1
+ return
fi
- if [ -r $full_sysfs_device_path/fcp_lun ]; then
- read lun < $full_sysfs_device_path/fcp_lun
+ sas_phy_address="$phy_address:$phy_port:$phy_id"
+ sas_rphy_dev="${sas_host_path}/${sas_phy_id}/${sas_rphy_id}/sas_rphy:${sas_rphy_id}"
+ if [ -e "$sas_rphy_dev/sas_address" ]; then
+ read rphy_address < $sas_rphy_dev/sas_address
+ read rphy_id < $sas_rphy_dev/phy_identifier
fi
- if [ -r $full_sysfs_device_path/hba_id ]; then
- read bus_id < $full_sysfs_device_path/hba_id
+ if [ -z "$rphy_address" ] ; then
+ : no initiator address
+ RESULT=1
+ return
fi
- if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
- # S/390 zfcp adapter
- d="ccw-$bus_id-zfcp-$wwpn:$lun"
- RESULT=0
+ sas_rphy_address="$rphy_address:$rphy_id"
+ controller_dev="${sas_host_path%/host[0-9]*}"
+ # SAS devices are always endpoints
+ d="sas-${sas_phy_address}-${sas_rphy_address}"
+ D="$controller_dev"
+ 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
- # DASD devices
- bus="ccw"
- adapter=${D##*/}
- d="$bus-$adapter"
- RESULT=0
+ d="usb-$usb_host_port:$port_num"
fi
- ;;
- */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
- # check for ieee1394 sbp2
- if test -f $D/ieee1394_id ; then
- read ieee1394_id < $D/ieee1394_id
- d="`echo ieee1394-${ieee1394_id} | sed -e 's@:@-@g'`"
- RESULT=0
+ D="$host_dev_path"
+ RESULT=0
+}
+
+handle_device () {
+ full_sysfs_path="$SYSFS$DEVPATH"
+ if [ -L $full_sysfs_path/subsystem ]; then
+ # new sysfs block layout
+ full_sysfs_path="${full_sysfs_path%/*}"
+ cd "$full_sysfs_path/subsystem";
+ subsys="`pwd -P`"
+ cd "$OPWD"
+ subsys="${subsys##*/}"
+ if [ "$subsys" == "block" ]; then
+ # parent is "block", it's a partition, move one up
+ full_sysfs_path="${full_sysfs_path%/*}"
+ fi
+ cd $full_sysfs_path
else
- handle_block_scsi "$D"
+ # old sysfs block layout
+ if [ ! -L $full_sysfs_path/device ] ; then
+ if [ -f $full_sysfs_path/range ] ; then return ; fi
+ 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
+ cd $full_sysfs_path/device
+ fi
+ 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"
+ ;;
+ */phy-[0-9]*:[0-9]*/*)
+ handle_sas "$D"
+ ;;
+ */fw-host[0-9]*/*)
+ handle_firewire "$D"
+ ;;
+ */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
+ handle_scsi "$D"
+ ;;
+ */usb[0-9]*/[0-9]*/*)
+ handle_usb "$D"
+ ;;
+ */pci[0-9]*:[0-9]*)
+ handle_pci "$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
- ;;
-
- *)
- : not handled
- RESULT=1
- return
-
- ;;
- esac
- # look for a partition
- if [ "$full_sysfs_class_path" != "$SYSFS$DEVPATH" ] ; then
- dp="`echo $SYSFS$DEVPATH | sed -e 's@^/.*/@@;s@^[^0-9]\{1,\}@@;s@.*_@@'`"
- case "$d" in
- *[0-9])
- d="${d}p${dp}"
- ;;
- *)
- d="${d}${dp}"
- ;;
- esac
- fi
- # done
- echo "ID_PATH=$d"
}
case "$TYPE" in
block)
- handle_block
- ;;
+ handle_device
+ echo "ID_PATH=$d"
+ ;;
+ scsi_tape)
+ handle_device
+ echo "ID_PATH=$d"
+ ;;
+ input)
+ handle_device
+ echo "ID_PATH=$d"
+ ;;
*)
- RESULT=1
- ;;
+ RESULT=1
+ ;;
esac
+
exit $RESULT