Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 1695 lines (1411 sloc) 39.2 KB
#! /bin/bash
# Copyright (c) 2004 International Business Machines
#
# 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; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Author Nathan Fontenot <nfont@linux.vnet.ibm.com>
#
# ofpathname - This utility provides a mechanism for converting a logical
# device name to an open firmware device path, and vice versa.
#
# TODO: This script doesn't handle floppy drives and token ring devices,
# perhaps they should be added in at some point.
#
OFPATHNAME="ofpathname"
VERSION="0.5"
FIND=/usr/bin/find
CAT=/bin/cat
PSERIES_PLATFORM=$(dirname $0)/pseries_platform
# Find out what platfrom we are running on. Hopefully this
# list will get expanded with time.
PLATFORM=$(sed /proc/cpuinfo -ne "s/^machine\t*: \(.*\)/\1/p")
case $PLATFORM in
EFIKA5K2\ *) PLATFORM=efika ;;
esac
# Usage statemnet
usage()
{
echo "Usage: $OFPATHNAME [OPTION] DEVICE"
echo "Provide logical device names <==> Open Firmware Device Path Conversion"
echo ""
echo "Optional arguments."
echo " -l Convert Open Firmware device pathname to"
echo " logical device name."
echo " -a Find matching Open Firmware device alias[es]."
echo " -q, --quiet Do not report failures, exit quietly"
echo " -V, --version Display version information and exit"
echo " -h, --help Display this help information and exit"
echo ""
}
show_version()
{
echo "$OFPATHNAME: Version $VERSION"
echo "Written by: Nathan Fontenot <nfont@linux.vnet.ibm.com>"
}
#
# err
# Common routine to print error messages for ofpathname. Since most of the
# error messages can be generated in multiple places, we put all the text
# here to avoid errors in duplicating the messages.
#
# The first and only parameteris the error message number, all of which
# are defined below as ERR_*.
#
ERR_NO_OFPATH=1
ERR_NO_SYSFS=2
ERR_NO_SYSFS_DEVINFO=3
ERR_NOT_CONFIG=4
ERR_NO_LOGDEV=5
err()
{
local emsg=$1
if [[ -n $be_quiet ]]; then
exit 1
fi
case $emsg in
1) echo "$OFPATHNAME: Could not retrieve Open Firmware device path"
echo " for logical device \"$DEVNAME_ARG\"." ;;
2) echo "$OFPATHNAME: sysfs (/sys) is needed and does not appear"
echo " to be mounted on this system." ;;
3) echo "$OFPATHNAME: Could not find sysfs information for logical"
echo " device \"$DEVNAME_ARG\"." ;;
4) echo "$OFPATHANME: Logical device \"$DEVNAME_ARG\" does not appear"
echo " to be configured." ;;
5) echo "$OFPATHNAME: Could not retrieve logical device name for"
echo " Open Firmware path \"$DEVNAME_ARG\"."
esac
exit 1
}
# is_hbtl
# return true if the link is in HBTL (Host:Bus:Target ID:LUN) format
is_hbtl()
{
local ln_name=$1;
local tmp="${ln_name//[^:]}"
if [[ ${#tmp} = 3 ]]; then
echo 1
else
echo 0
fi
}
#
# get_link
# return the directory path that a link points to.
# The only parameter is the link name.
#
get_link()
{
local ln_name=$1;
echo `ls -l $ln_name 2>/dev/null | awk -F"->" '{print $2}'`
}
#
# get_hbtl
# Given a path that ends in an HBTL (Host:Bus:Target ID:LUN), break it apart
# into its constituent parts in the global vars HOST, BUS, TARGET and LUN
#
# #1 path ending in HBTL
#
get_hbtl()
{
local hbtl
HBTL=${1##*/}
hbtl=$HBTL
HOST=${hbtl%%:*}
hbtl=${hbtl#*:}
BUS=${hbtl%%:*}
BUS=`echo "ibase=10;obase=16; $BUS" | bc | tr "[:upper:]" "[:lower:]"`
hbtl=${hbtl#*:}
ID=${hbtl%%:*}
ID=`echo "ibase=10;obase=16; $ID" | bc | tr "[:upper:]" "[:lower:]"`
LUN=${hbtl#*:}
LUN=`echo "ibase=10;obase=16; $LUN" | bc | tr "[:upper:]" "[:lower:]"`
}
#
# get_scsi_disk_no
# Given a path that ends in an HBTL, convert the HBTL values into a
# virtual disk number (not sure what the real terminology is for it).
# To do the conversion, the HBTL (A:B:C:D) is split apart and
# calculated as;
# no = (0x1000000 | C << 16 | D)
#
# $1 path ending in HBTL
get_scsi_disk_no()
{
get_hbtl $1
local C D
C=$((0x$ID << 16))
D=$((0x$LUN))
local vdiskno vdisk
typeset -i vdiskno
vdiskno=$((0x1000000 | $C | $D ))
vdisk=${vdiskno##-}
vdisk=`echo \`bc << END
ibase=10
obase=16
$vdisk
END\``
local extrazeroes="00000000"
echo $vdisk$extrazeroes
}
#
# get_vdisk_no
# Given a path that ends in an HBTL, convert the HBTL values into a
# virtual disk number (not sure what the real terminology is for it).
# To do the conversion, the HBTL (A:B:C:D) is split apart and
# calculated as;
# no = (0x8000 | B << 8 | C << 5 | D) * 1000000000000
#
# $1 path ending in HBTL
#
get_vdisk_no()
{
get_hbtl $1
local B C D
typeset -i B C D
B=$((0x$ID << 8))
C=$((0x$BUS << 5))
D=$((0x$LUN))
local vdiskno vdisk
typeset -i vdiskno
vdiskno=$((0x8000 | $B | $C | $D ))
vdisk=${vdiskno##-}
vdisk=`echo \`bc << END
ibase=10
obase=16
$vdisk
END\``
local extrazeroes="000000000000"
echo $vdisk$extrazeroes
}
#
# get_usb_vdisk_no
# Given a path that ends in an HBTL, convert the HBTL values into a
# virtual disk number (not sure what the real terminology is for it).
# To do the conversion, the HBTL (A:B:C:D) is split apart and
# calculated as;
# no = (0x1000000 | (usb_port << 16) | D);
#
# $1 path ending in HBTL
#
get_usb_vdisk_no()
{
get_hbtl $1
local usb_port=$2
local B
B=$((0x$usb_port << 16))
local vdiskno vdisk
vdiskno=$((0x1000000 | $B | $LUN ))
vdisk=${vdiskno##-}
vdisk=$(bc << END
ibase=10
obase=16
$vdisk
END
)
local extrazeroes="00000000"
echo $vdisk$extrazeroes
}
#
# get_usb_storage_no
# Get usb device storage (port) number which is captured in
# devpath file
#
# $1 starting directory to look for devpath file
get_usb_storage_no()
{
for dir in `$FIND /sys -name $1`; do
# Move up until we find one with a devpath link
goto_dir $dir "devpath" 0
if [ $? -eq 0 ]; then
break;
fi
done;
if [ -f $PWD/devpath ]; then
echo `$CAT $PWD/devpath`
else
err $ERR_NOT_CONFIG
fi
}
#
# goto_dir
# This looks for a given file in a given directory or any parents of the
# given directory.
#
# $1 starting directory
# $2 file to search for
# $3 on_exit behavior on error
goto_dir()
{
local start_dir=$1
local fname=$2
local found=0
local on_exit=1
if [[ $# -eq 3 ]]; then
on_exit=$3
fi
cd $start_dir
while [[ $PWD != "/" ]]; do
ls $fname >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
found=1
break
fi
cd ..
done
if [[ $found -eq 0 ]]; then
if [[ $on_exit -eq 1 ]]; then
err $ERR_NO_SYSFS_DEVINFO
else
return 1
fi
fi
}
#
# find_dir
# This looks for a given file in a given directory or any parents of the
# given directory. This differs from goto_dir in that we don't actually try
# to cd to the directories, we just return the directory name if found.
#
# $1 starting directory
# $2 file to search for
# $3 on_exit behavior on error
find_dir()
{
local dir=$1
local fname=$2
while [[ -n $dir ]]; do
/bin/ls $dir/$fname >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo $dir
return
fi
dir=${dir%/*}
done
}
#
# is_pata_dev
# Check to see if this is a PATA device
#
is_pata_dev()
{
local this_dir=$PWD
local sysfs_dir
local udev_path
local udevinfo="/usr/bin/udevinfo"
local udevadm="/sbin/udevadm"
if [[ -a $udevadm ]]; then
udev_path=`$udevadm info --query=path --name=$DEVNAME`
elif [[ -a $udevinfo ]]; then
udev_path=`$udevinfo -q path -n $DEVNAME`
else
echo "no"
return
fi
if [[ -z $udev_path ]]; then
echo "no"
else
sysfs_dir=`get_link -f /sys/$udev_path/device`
if [[ ! -d $sysfs_dir ]]; then
echo "no"
else
goto_dir $sysfs_dir devspec
DEVTYPE=$(cat /proc/device-tree/$(cat $PWD/devspec)/device_type)
if [[ $DEVTYPE = "ata" ]]; then
echo "yes"
else
echo "no"
fi
fi
fi
cd $this_dir
}
#
# print_aliases
# Print the aliases from /proc/device-tree/aliases for the specified device
#
print_aliases()
{
dev=$1
local found=0
shopt -s nullglob
for i in /proc/device-tree/aliases/*; do
if sed -e "s/\x00$//g" $i | grep -qx "$dev" ; then
echo ${i##*/}
found=1
fi
done
if [[ $found = "0" ]]; then
echo "No aliases found."
exit 1
else
exit 0
fi
}
get_slave()
{
cd /sys/class/*/$1
while [[ -n "`ls slaves 2> /dev/null`" ]]; do
cd `echo slaves/* | head -n1 | cut -d " " -f1`;
done
$FIND /dev -name "`basename $PWD`"
}
#
# is_net_interface
# Check to see if this is a network interface
#
is_net_interface()
{
local res
res=`$FIND /sys/class/net -name $1`
if [[ ${#res} = 0 ]]; then
echo "no"
else
echo "yes"
fi
}
#
# logical_to_ofpathname
# Conversion for logical device name to an Open Firmware device path
#
logical_to_ofpathname()
{
local is_cdrom
# follow any links to the real device name
while [[ -L $DEVNAME ]]; do
DEVNAME=`get_link $DEVNAME`
done
while [[ -L /dev/$DEVNAME ]]; do
DEVNAME=`get_link /dev/$DEVNAME`
done
DEVICE=${DEVNAME##*/}
DEVNODE=${DEVICE%%[0-9]*}
# try to determine if this is a cdrom device
if [[ ${DEVNAME_ARG##*/} = cdrom ]]; then
is_cdrom=yes
elif [[ `get_link /dev/cdrom` = /dev/$DEVICE ]]; then
is_cdrom=yes
else
is_cdrom=no
fi
case $DEVICE in
eth*) l2of_ethernet ;;
hf*) l2of_hfi ;;
sd* | sr*) # PATA devices appear as sd*, but should be converted
# using the ide logic
is_pata=$(is_pata_dev $DEVNAME)
if [[ $is_pata = "yes" ]]; then
l2of_ide
else
l2of_scsi
fi ;;
hd*) l2of_ide ;;
vd*) l2of_vd ;;
fd*) echo "no fd support yet" ;;
mpath*)
DEVNAME=$(printf "dm-%d" `stat -c "%T" /dev/mapper/$DEVICE`)
logical_to_ofpathname
;;
dm-*)
DEVNAME=`get_slave $DEVICE`
logical_to_ofpathname
exit
;;
nvme*) l2of_nvme ;;
*) # check if the device is a network interface
is_net=$(is_net_interface $DEVICE)
if [[ $is_net = "yes" ]]; then
l2of_ethernet
fi ;;
esac
if [[ -z $OF_PATH ]]; then
err $ERR_NO_OFPATH
fi
if [[ $is_cdrom = yes ]]; then
OF_PATH=$OFPATH:1\\ppc\\bootinfo.txt
fi
if [[ $do_alias = "1" ]]; then
print_aliases $OF_PATH
else
echo $OF_PATH
fi
}
#
# l2of_ide
# Conversion routine for logical => OF path of ide devices
#
l2of_ide()
{
cd /sys/block/$DEVICE
local link=`get_link "device"`
if [[ -z $link ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
cd $link
# get the device number
local devdir=${PWD##/*/}
local channelno=${devdir%%\.*}
local devno=${devdir##*\.}
goto_dir $PWD "devspec"
OF_PATH=`$CAT $PWD/devspec`
if [[ -z $OF_PATH ]]; then
err $ERR_NO_OFPATH
fi
# PCI ATA controller nodes (found on some Macs) have one child per IDE
# channel.
case `$CAT "/proc/device-tree/$OF_PATH/device_type"` in
pci-ata | pci-ide) OF_PATH=$OF_PATH/@$channelno ;;
esac
# On Efika, obtained devno "0:0:0:0" doesn't match actual device.
# Note: according to vendor, "0,0" means primary master. Secondary
# channel is not present, and primary slave is rare enough that we
# can reasonably ignore it.
if [ "$PLATFORM" = "efika" ] ; then
devno=0,0
fi
OF_PATH=$OF_PATH/disk@$devno
}
#
# l2of_vd
# Conversion routine for logical => OF path of virtio block devices
#
l2of_vd()
{
local found=0
# There may be many instances of DEVICE under /sys
for dir in `$FIND /sys -name $DEVICE`; do
# Move up until we find one with a device link
goto_dir $dir "device" 0
if [ $? -eq 0 ]; then
found=1;
break;
fi
done;
if [ $found -eq 0 ]; then
err $ERR_NOT_CONFIG
fi
local link=`get_link "device"`
if [[ -z $link ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
cd $link
goto_dir $PWD "devspec"
OF_PATH=`$CAT $PWD/devspec`
if [[ -z $OF_PATH ]]; then
err $ERR_NO_OFPATH
fi
}
#
# l2of_ethernet
# Conversion routine for logical => OF path of ethernet devices
#
l2of_ethernet()
{
for syspath in `$FIND /sys -name $DEVICE 2> /dev/null`; do
if [[ -e $syspath/device/devspec ]]; then
OF_PATH=`$CAT $syspath/device/devspec`
break
fi
done
if [[ -z $OF_PATH ]]; then
err $ERR_NO_OFPATH
fi
}
#
# l2of_hfi
# Conversion routine for logical => OF path of HFI devices
#
l2of_hfi()
{
local hfnum=${DEVICE##hf}
local hfpath
if [[ $hfnum = "0" || $hfnum = "2" ]]; then
hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | head -n 1`
elif [[ $hfnum = "1" || $hfnum = "3" ]]; then
hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | tail -n 1`
else
err $ERR_NO_OFPATH
fi
OF_PATH=${hfpath##/proc/device-tree}
}
#
# l2of_nvme
# Conversion routine for logical => OF path of nvme devices
#
l2of_nvme()
{
# OF path: <devspec>/namespace@<namespace-id>:<partition-number>
# disk: nvmeX, nvmeXnY; not nvmeXnYpZ
local devdisk="${DEVICE%p[0-9]*}"
# namespace id: Y in nvmeXnY, nvmeXnYpZ
local devnsid="${devdisk#nvme[0-9]*n}"
if [[ $devnsid = $devdisk ]]; then
devnsid='' # no namespace id
fi
# partition number: Z in nvmeXnYpZ
local devpart="${DEVICE##*p}"
if [[ $devpart = $DEVICE ]]; then
devpart='' # no partition number
fi
# Get the device-tree device specification (devspec).
local dir
local found=0
for dir in `$FIND /sys/devices -name "$DEVICE"`; do
cd $dir
goto_dir $PWD "device/devspec"
devspec=`$CAT $PWD/device/devspec`
if [[ -n $devspec ]]; then
found=1
break
fi
done
if [[ $found -eq 0 ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
if [[ -z $devspec ]]; then
err $ERR_NO_OFPATH
fi
# OF path: <devspec>/namespace@<namespace-id>:<partition-number>
OF_PATH="$devspec"
# No namespace id (nY) specified.
if [[ -z $devnsid ]]; then
return
fi
# Device type is usually 'namespace'.
# Get it from device-tree just in case.
devtype=`$CAT /proc/device-tree${devspec}/namespace/name`
if [[ -z $devtype ]]; then
err $ERR_NO_OFPATH
fi
OF_PATH="$OF_PATH/$devtype@$devnsid"
# No partition (pZ) specified.
if [[ -z $devpart ]]; then
return
fi
OF_PATH="${OF_PATH}:${devpart}"
}
#
# int_to_scsilun
# Conversion routine for SCSI HBTL LUN => SCSI LUN name
#
int_to_scsilun()
{
local lunint=$1
local A B C D
A=$(( ($lunint >> 8) & 0xff ))
B=$(($lunint & 0xff))
C=$(( ($lunint >> 24) & 0xff ))
D=$(( ($lunint >> 16) & 0xff ))
local lunstr=$(printf "%02x%02x%02x%02x00000000" $A $B $C $D)
lunstr=`echo $lunstr | sed 's/^[0]*//'`
echo "$lunstr"
}
#
# scsilun_to_int
# Conversion routine for SCSI LUN name => SCSI HBTL LUN
#
scsilun_to_int()
{
local lunstr=$1
local A B C D L
L=${lunstr/00000000}
L=`echo $L | tr "[a-z]" "[A-Z]"`
L=`echo "ibase=16;obase=A; $L" | bc`
A=$(( ($L >> 8) & 0xff ))
B=$(($L & 0xff))
C=$(( ($L >> 24) & 0xff ))
D=$(( ($L >> 16) & 0xff ))
L=$(( (($A << 24) | ($B << 16) | ($C << 8) | $D) ))
echo "$L"
}
get_fc_scsilun()
{
local lun=$1
local L
L=`echo $lun | tr "[a-z]" "[A-Z]"`
L=`echo "ibase=16;obase=A; $L" | bc`
local fc_lun=`int_to_scsilun $L`
echo "$fc_lun"
}
get_fc_wwpn()
{
local start_dir=$1
for f in `$FIND -H $start_dir -maxdepth 2 -name port_name`; do
local wwpn=`$CAT $f`
break
done
# strip the leading 0x
wwpn=${wwpn:2}
echo "$wwpn"
}
#
# l2of_scsi
# Converion routine for logical => OF path of scsi devices
#
l2of_scsi()
{
local found=0
local devtype
# There may be many instances of DEVICE under /sys
for dir in `$FIND /sys -name $DEVICE`; do
# Move up until we find one with a device link
goto_dir $dir "device" 0
if [ $? -eq 0 ]; then
found=1;
break;
fi
done;
if [ $found -eq 0 ]; then
err $ERR_NOT_CONFIG
fi
# follow the 'device' link
local link=`get_link "device"`
if [[ -z $link ]]; then
# device may not be a link
link=device
fi
get_hbtl $link
cd $link
# save the name of the current directory, we may need it later...
local device_dir=${PWD##/*/}
local device_path=$PWD
# move up directories until we find one with devspec information
goto_dir $PWD "devspec"
OF_PATH=`$CAT $PWD/devspec`
if [[ -z $OF_PATH ]]; then
err $ERR_NO_OFPATH
fi
local vdev=${OF_PATH%/*}
local fc=${OF_PATH%@*}
fc=${fc##/*/}
if [[ -e /proc/device-tree$OF_PATH/device_type ]]; then
devtype=`tr -d '\0' < /proc/device-tree$OF_PATH/device_type`;
if [[ $devtype = "fcp" || $devtype = "scsi-fcp" ]]; then
fc="fibre-channel";
fi
fi
if [[ $fc = "usb" ]]; then
local hub_no storage_no disk_no
storage_no=`get_usb_storage_no $DEVICE`
if [[ $storage_no = *.* ]]; then
hub_no=${storage_no%%.*}
storage_no=${storage_no##*.}
fi
disk_no=`get_usb_vdisk_no $device_dir $storage_no`
if [[ -z $hub_no ]]; then
OF_PATH=$OF_PATH/storage\@$storage_no/disk\@$disk_no
else
OF_PATH=$OF_PATH/hub\@$hub_no/storage\@$storage_no/disk\@$disk_no
fi
elif [[ $fc = "fibre-channel" ]]; then
local wwpn=`get_fc_wwpn "$device_path/../../fc_remote_ports*"`
if [[ ! -e /proc/device-tree$OF_PATH/disk ]]; then
for dir in `$FIND /proc/device-tree$OF_PATH -type d`; do
if [[ -e $dir/disk ]]; then
OF_PATH=${dir##/proc/device-tree}
break;
fi
done
fi
OF_PATH=$(printf "%s/disk@%s" $OF_PATH $wwpn)
if [[ $LUN != "0" ]]; then
local fc_lun=`get_fc_scsilun $LUN`
OF_PATH=$(printf "%s,%s" $OF_PATH $fc_lun)
fi
elif [[ $vdev = "/vdevice" ]]; then
# get the v-device data
local tmp=${OF_PATH//\/vdevice/}
local vdevtype=${tmp%@*}
if [[ $vdevtype = "/vfc-client" ]]; then
local vfc_lun=`get_fc_scsilun $LUN`
local wwpn=`get_fc_wwpn "$device_path/../../fc_remote_ports*"`
OF_PATH=$(printf "%s/disk@%s,%s" $OF_PATH $wwpn $vfc_lun)
else
local i vdiskno
goto_dir $device_path $device_dir
vdiskno=`get_vdisk_no $device_dir`
OF_PATH=$OF_PATH/disk\@$vdiskno
fi
elif [[ -d /proc/device-tree$OF_PATH/sas ]]; then
local vendor_id sas_id
vendor_id=`od -tx /proc/device-tree/$OF_PATH/vendor-id`
vendor_id=`echo $vendor_id | cut -d " " -f 2`
if [[ $vendor_id = "00001000" ]]; then
local dev_id
goto_dir $device_path "sas_end_device*"
dev_id=${PWD##*-}
sas_id=`cat /sys/class/sas_device/end_device-$dev_id/sas_address`
sas_id=${sas_id##0x}
OF_PATH=$(printf "%s/sas/disk@%s" $OF_PATH $sas_id)
if [[ $LUN != "0" ]]; then
local LUNSTR=`int_to_scsilun $LUN`
OF_PATH=$(printf "%s,%s" $OF_PATH $LUNSTR)
fi
else
local B T L
local fwtype="0"
if [[ -e /sys/class/scsi_host/host$HOST/fw_type ]]; then
fwtype=`$CAT /sys/class/scsi_host/host$HOST/fw_type`
fi
if [[ $fwtype = "1" ]]; then
goto_dir $device_path "device_id"
sas_id=`$CAT $PWD/device_id`
sas_id=${sas_id##0x}
OF_PATH=$(printf "%s/sas/disk@%s" $OF_PATH $sas_id)
if [[ $LUN != "0" ]]; then
local LUNSTR=`int_to_scsilun $LUN`
OF_PATH=$(printf "%s,%s" $OF_PATH $LUNSTR)
fi
else
B=`echo $BUS | tr "[a-z]" "[A-Z]"`
B=`echo "ibase=16;obase=A; $B" | bc`
T=`echo $ID | tr "[a-z]" "[A-Z]"`
T=`echo "ibase=16;obase=A; $T" | bc`
L=`echo $LUN | tr "[a-z]" "[A-Z]"`
L=`echo "ibase=16;obase=A; $L" | bc`
sas_id=$(( ($B << 16) | ($T << 8) | $L ))
OF_PATH=$(printf "%s/sas/disk@%x" $OF_PATH $sas_id)
if [[ $LUN != "0" ]]; then
OF_PATH=$(printf "%s,%x" $OF_PATH $LUN)
fi
fi
fi
else
# make sure the "scsi" information is on the end of the path
local scsi_name=${OF_PATH##/*/}
scsi_name=${scsi_name%%@*}
if [[ $scsi_name != "scsi" ]]; then
scsi_name="scsi@$BUS"
OF_PATH=$OF_PATH/$scsi_name
fi
local modalias=""
goto_dir $device_path "device"
if [ $? -eq 0 ]; then
modalias=`$CAT $PWD/modalias`
fi
if [[ $modalias =~ "virtio" ]]; then
local diskno
diskno=`get_scsi_disk_no $device_dir`
OF_PATH=$OF_PATH/disk\@$diskno
else
OF_PATH=$OF_PATH/sd@$ID,$LUN
fi
fi
}
#
# ofpathname_to_logical
# Conversion for Open Firmware device paths to logical device names
#
ofpathname_to_logical()
{
DEVPATH=${DEVNAME%/*}
DEVICE=${DEVNAME##/*/}
DEVTYPE=${DEVICE%\@*}
SAS=${DEVPATH##/*/}
FC=${SAS%%\@*}
if [[ $do_alias = "1" ]]; then
print_aliases $OF_PATH
fi
if [[ $DEVTYPE = "disk" && $DEVICE != ${DEVICE%:*} ]]; then
DEVTYPE=${DEVICE%:*}
fi
if [[ $DEVTYPE = "disk" && $FC = "v-scsi" ]]; then
DEVTYPE="v-scsi"
fi
if [[ $DEVTYPE = "disk" && $FC = "scsi" ]]; then
DEVTYPE="scsi"
fi
if [[ $DEVTYPE = "disk" && $SAS = "sas" ]]; then
DEVTYPE="sas"
fi
if [[ $DEVTYPE = "disk" && $FC = "vfc-client" ]]; then
DEVTYPE="vfc"
fi
if [[ $DEVTYPE = "disk" && $FC = "fibre-channel" ]]; then
DEVTYPE="fc"
fi
if [[ $DEVTYPE = "disk" && $FC = "QLGC,qlc" ]]; then
DEVTYPE="fc"
fi
if [[ $DEVTYPE = "disk" && $FC = "fp" ]]; then
DEVTYPE="fc"
fi
if [[ $DEVTYPE = "disk" && $FC = "storage" ]]; then
local devpath=$DEVPATH
DEVPATH=${devpath%/*}
DEVTYPE="usb"
if [[ $DEVNAME = *hub* ]]; then
devpath=$DEVPATH
DEVPATH=${devpath%/*}
fi
fi
if [[ $DEVTYPE = "namespace" ]]; then
DEVTYPE="nvme"
fi
# Remove any possible cdrom data from DEVICE
if [[ ${DEVICE##*,} = "\ppc\bootinfo.txt" ||
${DEVICE##*,} = \ppc\bootinfo.txt ]]; then
DEVICE=${DEVICE%,*}
fi
# Remove any possible yaboot suffix from DEVICE
if [[ ${DEVICE##*,} = "yaboot" ]]; then
DEVICE=${DEVICE%,*}
fi
case $DEVTYPE in
sd* | scsi* ) of2l_scsi ;;
sas ) of2l_sas ;;
vfc ) of2l_vfc ;;
fc ) of2l_fc ;;
v-scsi | disk ) of2l_vscsi
if [[ -z $LOGICAL_DEVNAME && $DEVTYPE = disk ]]; then
of2l_ide
fi ;;
eth* | l-lan ) of2l_ethernet ;;
vnic ) of2l_ethernet ;;
hfi-ethernet* ) of2l_hfi ;;
disk* ) of2l_ide ;;
usb ) of2l_usb ;;
nvme ) of2l_nvme ;;
esac
if [[ -z $LOGICAL_DEVNAME ]]; then
err $ERR_NO_LOGDEV
fi
# See if this device is the cdrom
if [[ `get_link "/dev/cdrom"` = $LOGICAL_DEVNAME ]]; then
LOGICAL_DEVNAME="cdrom"
fi
echo $LOGICAL_DEVNAME
}
#
# of2l_ide
# Conversion routine for OF path => logical name for ide devices
#
of2l_ide()
{
local dir
for dir in `$FIND /sys/block -name 'hd*'`; do
# get devno
local devno=${DEVICE##*@}
devno=${devno%%:*}
cd $dir
local link=`get_link "device"`
if [[ -n $link ]]; then
cd $link
# see if this is the correct device
local this_devno=${PWD##*\.}
if [[ $devno -eq $this_devno ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
break
fi
fi
fi
done
}
#
# of2l_ethernet
# Conversion routine for OF path => logical names of ethernet devices
#
of2l_ethernet()
{
local dir
# strip off ip info if present
local devname=${DEVNAME%%:*}
local netdir="/sys/class/net"
for dir in `ls $netdir`; do
local devdir=`find_dir $netdir/$dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -z $link ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
cd $link
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $devname ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
done
}
#
# of2l_hfi
# Conversion routine for OF path => logical names of HFI devices
#
of2l_hfi()
{
# strip off ip info if present
local devname=${DEVNAME%%:*}
local hfpath
hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | head -n 1`
hfpath=${hfpath##/proc/device-tree}
if [[ $hfpath = $devname ]] ; then
LOGICAL_DEVNAME="hf0"
else
hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | tail -n 1`
hfpath=${hfpath##/proc/device-tree}
if [[ $hfpath = $devname ]] ; then
LOGICAL_DEVNAME="hf1"
else
err $ERR_NO_LOGDEV
fi
fi
}
#
# of2l_usb
# Conversion routine for OF path => logical names of usb devices
#
of2l_usb()
{
DEV_HBTL_NO=${DEVICE##*\@}
local dir
for dir in `$FIND /sys/block -name 's[dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
local vdisk_no
if [[ -n $link ]]; then
local port_no storage_no target
target=${link##*/}
port_no=`get_usb_storage_no $target`
storage_no=${port_no##*.}
vdisk_no=`get_usb_vdisk_no $target $storage_no`
cd $link
if [[ $vdisk_no = $DEV_HBTL_NO ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME=${dir##/*/}
return
fi
fi
fi
done
}
#
# of2l_vscsi
# Conversion routine for OF path => logical names of virtual scsi devices
#
of2l_vscsi()
{
DEV_HBTL_NO=${DEVICE##*\@}
local dir
for dir in `$FIND /sys/block -name 's[dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -n $link ]]; then
local vdiskno=`get_vdisk_no $link`
cd $link
if [[ $vdiskno = $DEV_HBTL_NO ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME=${dir##/*/}
return
fi
fi
fi
done
}
#
# of2l_scsi
# Conversion routine for OF path => logical names of scsi devices
#
of2l_scsi()
{
DEV_HBTL_NO=${DEVICE##*\@}
DEV_TARGET=${DEVICE##*\@}
DEV_TARGET=${DEV_TARGET%%,*}
DEV_LUN=${DEVICE##*,}
# At this point DEV_LUN may be in the form X:Y, we're only interested
# in the X component.
DEV_LUN=${DEV_LUN%%:*}
local dir
for dir in `$FIND /sys/block -name '[sv][dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -z $link ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
local hbtl=`is_hbtl $link`
local diskno
# Do not call get_hbtl for virtio block devices
if [[ $hbtl = 1 ]]; then
get_hbtl $link
diskno=`get_scsi_disk_no $link`
fi
cd $link
# save the name of the current directory, we may need it later...
local device_dir=${PWD##/*/}
if [[ $hbtl = 0 || $diskno = $DEV_HBTL_NO ||
($ID = $DEV_TARGET && $LUN = $DEV_LUN) ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
# Handle virtio block devices
if [[ $hbtl = 0 && $devspec = $DEVNAME ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
local scsi_name=${devspec##/*/}
scsi_name=${scsi_name%%@*}
if [[ $scsi_name != "scsi" ]]; then
scsi_name="scsi@$BUS"
devspec=$devspec/$scsi_name
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
fi
done
}
#
# of2l_sas
# Conversion routine for OF path => logical names of sas devices
#
of2l_sas()
{
local matchtype dir
DEV_NAME=${DEVICE##*\@}
DEV_ID=${DEV_NAME%%,*}
LUN=${DEV_NAME/$DEV_ID}
LUN=${LUN/,/}
if [[ ${#LUN} = 0 ]]; then
LUN="0"
fi
lunint=`scsilun_to_int $LUN`
PCI_ID=${DEVPATH%%/sas*}
vendor_id=`od -tx /proc/device-tree/$PCI_ID/vendor-id`
vendor_id=`echo $vendor_id | cut -d " " -f 2`
if [[ $vendor_id = "00001000" ]]; then
matchtype="libsas"
else
matchtype="ipr32"
fi
for dir in `$FIND /sys/class/scsi_host -maxdepth 1 -name 'host*'`; do
cd $dir
local link=`get_link "device"`
cd $link
cd ..
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $PCI_ID ]]; then
# check for ipr64
if [[ -e $dir/fw_type ]]; then
local fwtype=`$CAT $dir/fw_type`
if [[ $fwtype = "1" ]]; then
matchtype="ipr64"
break
fi
fi
break
fi
done
for dir in `$FIND /sys/block -name 's[dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -z $link ]]; then
err $ERR_NO_SYSFS_DEVINFO
fi
get_hbtl $link
cd $link
# save the name of the current directory, we may need it later...
local device_dir=$PWD
local B T L
B=`echo $BUS | tr "[a-z]" "[A-Z]"`
B=`echo "ibase=16;obase=A; $B" | bc`
T=`echo $ID | tr "[a-z]" "[A-Z]"`
T=`echo "ibase=16;obase=A; $T" | bc`
L=`echo $LUN | tr "[a-z]" "[A-Z]"`
L=`echo "ibase=16;obase=A; $L" | bc`
if [[ $matchtype = "ipr32" ]]; then
local sas_id=$((($B << 16) | ($T << 8) | $L))
sas_id=`echo "ibase=A;obase=16; $sas_id" | bc`
sas_id=`echo $sas_id | tr "[A-Z]" "[a-z]"`
if [[ $sas_id = $DEV_ID ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec/sas = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
elif [[ $matchtype = "ipr64" ]]; then
if [[ -e $devdir/device/device_id ]]; then
local deviceid=`$CAT $devdir/device/device_id`
deviceid=${deviceid##0x}
if [[ $deviceid != $DEV_ID ]]; then
continue
fi
if [[ $L = $lunint ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec/sas = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
fi
elif [[ $matchtype = "libsas" ]]; then
local dev_id
goto_dir $device_dir "sas_end_device*" 0
dev_id=${PWD##*-}
if [[ ! -e /sys/class/sas_device/end_device-$dev_id/sas_address ]]; then
continue
fi
sas_id=`cat /sys/class/sas_device/end_device-$dev_id/sas_address`
sas_id=${sas_id##0x}
if [[ $sas_id != $DEV_ID ]]; then
continue
fi
if [[ $L = $lunint ]]; then
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec/sas = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
else
err $ERR_NO_LOGDEV
fi
done
}
#
# of2l_vfc
# Conversion routine for OF path => logical names of vFC devices
#
of2l_vfc()
{
DEV_ID=${DEVICE##*\@}
OF_WWPN=${DEV_ID%%,*}
OF_LUN=${DEV_ID##$OF_WWPN}
OF_LUN=${OF_LUN#,}
OF_LUN=`echo $OF_LUN | sed 's/^[0]*//'`
local dir
for dir in `$FIND /sys/block -name 's[dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -z $link ]]; then
continue
fi
get_hbtl $link
cd $link
link=$PWD
local device_dir=${PWD##/*/}
goto_dir $PWD "devspec"
OF_PATH=`$CAT $PWD/devspec`
if [[ -z $OF_PATH ]]; then
err $ERR_NO_LOGDEV
fi
local vdev=${OF_PATH%/*}
local tmp=${OF_PATH//\/vdevice/}
local vdevtype=${tmp%@*}
if [[ $vdevtype != "/vfc-client" ]]; then
continue
fi
local vfc_lun=`get_fc_scsilun $LUN`
local wwpn=`get_fc_wwpn "$link/../../fc_remote_ports*"`
if [[ $vfc_lun = $OF_LUN && $wwpn = $OF_WWPN ]]; then
if [[ $OF_PATH = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
done
}
#
# of2l_fc
# Conversion routine for OF path => logical names of FC devices
#
of2l_fc()
{
DEV_ID=${DEVICE##*\@}
OF_WWPN=${DEV_ID%%,*}
OF_LUN=${DEV_ID/$OF_WWPN}
OF_LUN=${OF_LUN/,/}
if [[ ${#OF_LUN} = 0 ]]; then
OF_LUN="0"
fi
lunint=`scsilun_to_int $OF_LUN`
local dir
for dir in `$FIND /sys/block -name 's[dr]*'`; do
# go up to find directory with 'device' link
local devdir=`find_dir $dir device`
if [[ -z $devdir ]]; then
continue
fi
cd $devdir
local link=`get_link "device"`
if [[ -z $link ]]; then
continue
fi
get_hbtl $link
cd $link
link=$PWD
# find device_path, not all dirs will have a fc_remote_ports
goto_dir $PWD "fc_remote_ports*" 0
if [[ $? -eq 1 ]]; then
continue
fi
device_path=$PWD
cd $link
local device_dir=${PWD##/*/}
goto_dir $PWD "devspec"
OF_PATH=`$CAT devspec`
if [[ -z $OF_PATH ]]; then
err $ERR_NO_LOGDEV
fi
local wwpn=`get_fc_wwpn "$device_path/fc_remote_ports*"`
if [[ $wwpn = $OF_WWPN ]]; then
local L
L=`echo $LUN | tr "[a-z]" "[A-Z]"`
L=`echo "ibase=16;obase=A; $L" | bc`
if [[ $L = $lunint ]]; then
LOGICAL_DEVNAME="${dir##*/}"
return
fi
fi
done
}
#
# of2l_nvme
# Conversion routine for OF path => logical name for nvme devices
#
of2l_nvme()
{
# get namespace id and partition number
local nsid_part=${DEVICE##*@} # <namespace-id>[:partition-number]
local nsid=${nsid_part%:*} # namespace id
local part # partition number
# set partition number only if ':' is present
case "${nsid_part}" in
*:*)
part=${nsid_part#*:}
;;
esac
local dir
local link
for dir in `$FIND /sys/block -name "nvme*n$nsid"`; do
cd $dir
link=`get_link "device"` # points to nvme[0-9]+ (non-namespace)
if [[ -n $link ]]; then
cd $link
else
continue
fi
link=`get_link "device"` # points to pci address dir
if [[ -n $link ]]; then
cd $link
else
continue
fi
goto_dir $PWD "devspec"
local devspec=`$CAT ./devspec 2>/dev/null`
if [[ $devspec = $DEVPATH ]]; then
LOGICAL_DEVNAME="${dir##*/}"
break
fi
done
if [[ -n $LOGICAL_DEVNAME ]] \
&& [[ -n $part ]]; then
if [[ -d "/sys/block/${LOGICAL_DEVNAME}/${LOGICAL_DEVNAME}p${part}" ]]; then
LOGICAL_DEVNAME="${LOGICAL_DEVNAME}p${part}"
else
LOGICAL_DEVNAME=''
fi
fi
}
#
# Main
#
. $PSERIES_PLATFORM
if [[ $platform = $PLATFORM_POWERNV ]]; then
echo "$OFPATHNAME: is not supported on the $platform_name platform"
exit 1
fi
if [[ "$#" -eq 0 ]]; then
usage
exit 0
fi
# default: convert logical => OFpath
do_of2l=0
# default: do not do alias lookups
do_alias=0
getopt -o "l:Vqh" -l "help,version,quiet" $@ > /dev/null 2>&1
while [[ -n $1 ]]; do
case "$1" in
-a) do_alias=1 ;;
-l) do_of2l=1
DEVNAME_ARG=$2
shift ;;
-V | --version) show_version
exit 0 ;;
-q | --quiet) be_quiet=1 ;;
-h | --help) usage
exit 0 ;;
*) DEVNAME_ARG=$1 ;;
esac
shift
done
DEVNAME=$DEVNAME_ARG
# double check device name
if [[ -z $DEVNAME ]]; then
usage
exit 1
fi
# We need sysfs
if [[ ! -d "/sys" ]]; then
err $ERR_NO_SYSFS
exit 1
fi
if [[ $do_of2l = "0" ]]; then
# logical devname => OF pathname
logical_to_ofpathname
else
# OF pathnmae => logical devname
ofpathname_to_logical
fi
exit 0