chiark / gitweb /
persistent links: add scsi tape links and usb path support
[elogind.git] / extras / path_id
old mode 100755 (executable)
new mode 100644 (file)
index 4ac7187..c17fc3c
 #      DEVPATH=/block/sda/sda3 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 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
 
-# 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
+# /class/block/sr0 -> /devices/pci0002:30/0002:30:0c.0/host0/target0:0:0/0:0:1:0
+# 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 
+# /class/block/sda -> /devices/pci0002:30/0002:30:0c.0/host0/target0:0:0/0:0:4:0
+# 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
+# /class/block/sda -> /devices/pci0001:00/0001:00:07.0/0001:05:0c.0/host0/target0:0:0/0:0:0:0
+# 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
+# /class/block/hda -> /devices/pci0002:02/0002:02:0d.0/ide0/0.0
+# 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
+# /class/block/hdc -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.00020000:ata-3/ide1/1.0
+# 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
+# /class/block/sr0 -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.0001f000:ata-4/ide0/0.1/host2/target2:0:0/2:0:0:0
+# 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
+# /class/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
+# 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
 # interface
 #
 # match order is important.
-# first IDE to find ide-scsi devices.
-# then SCSI
-# first usb-storage
-# then firewire sbp2
-# then the rest
+# first IDE to find ide-scsi devices, then SCSI
+# first usb-storage, then firewire sbp2, then the rest
 
 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
@@ -87,31 +81,30 @@ if [ -z "$DEVPATH" ] ; then
     esac
 fi
 
-if [ ! -d $SYSFS$DEVPATH ] ; then
-    exit 1
-fi
-if [ ! -f $SYSFS$DEVPATH/dev ] ; then
+if [ ! -e $SYSFS$DEVPATH/dev ] ; then
     exit 1
 fi
 
 case "$DEVPATH" in
-    /block/*)
-       TYPE=block
+    /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 () {
+get_port_offset () {
     local type offset port
     type=$1
     offset=$2
@@ -120,9 +113,28 @@ get_port () {
        port="${i#$type}"
        if [ "$port" -lt "$offset" ] ; then offset=$port ; fi
     done
-    if [ "$port" != "0" ] ; then
-       echo $(($2 - $offset))
-    fi
+    echo $offset
+}
+
+handle_pci () {
+    local DEV=$1
+    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
+
+    d="pci-$pci_id-$d"
+    D="$host_dev_path"
+    RESULT=0
 }
 
 handle_block_ide () {
@@ -131,42 +143,15 @@ handle_block_ide () {
        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
-                               ;;
-                               *)
-                               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
+
+       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
+       case "${port#*.}" in
                 0)
                 channel=0
                 ;;
@@ -176,154 +161,231 @@ handle_block_ide () {
                 *)
                 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"
-               ;;
-               *)
-               d="pci-${d##*/}"
-               # d="`echo $d | sed -e 's@^.*/\([^/]\{1,\}\)/.@pci-\1@'`"
-               ;;
-       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_block_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"
-               ;;
-               *)
-               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_block_firewire () {
+    :handle_block_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_block_fc () {
+: handle_block_fc $*
        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%/*}"
+       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_sas () {
+    : handle_block_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
+       if [ -z "$phy_address" ] ; then
+           : no initiator address
+           RESULT=1
+           return
+       fi
+       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 [ -z "$rphy_address" ] ; then
+           : no initiator address
+           RESULT=1
+           return
+       fi
+       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
-       : 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'`"
-       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}"
-       fi
-       d="$d:$cil"
-       RESULT=0
+       : 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_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
+    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
+       # 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
-    cd $full_sysfs_class_path/device
-    full_sysfs_device_path="`$pwd_cmd`"
+    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_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
@@ -345,46 +407,73 @@ handle_block () {
            d="$bus-$adapter"
            RESULT=0
        fi
+       D=
+       ;;
+       */rport-[0-9]*:[0-9]*-[0-9]*/*)
+       handle_block_fc "$D"
+       ;;
+       */phy-[0-9]*:[0-9]*/*)
+       handle_block_sas "$D"
+       ;;
+       */fw-host[0-9]*/*)
+       handle_block_firewire "$D"
        ;;
        */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
-       else
-           handle_block_scsi "$D"
-       fi
+       handle_block_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
-    # 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}"
-           ;;
+    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"
+               ;;
            *)
-               d="${d}${dp}"
+               mode=""
                ;;
        esac
+       if [ "$d" ]; then
+           d="$d-${rewind}st${mode}"
+       fi
     fi
-    # done
     echo "ID_PATH=$d"
 }
 
 case "$TYPE" in
-       block)
+    block)
        handle_block
        ;;
-       *)
+    scsi_tape)
+       handle_block
+       ;;
+    input)
+       handle_usb $SYSFS$DEVPATH/device
+       ;;
+    *)
        RESULT=1
        ;;
 esac