###############################################################################
##
## ofpath: determine OpenFirmware path from unix device node
-## Copyright (C) 2000, 2001, 2002 Ethan Benson
+## Copyright (C) 2000, 2001, 2002, 2003 Ethan Benson
##
## Portions based on show_of_path.sh:
##
## Copyright (C) 2000 Olaf Hering <olh@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; either version 2
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
PRG="${0##*/}"
-VERSION=1.0.3-rc1
+VERSION=1.0.7
DEBUG=0
export LC_COLLATE=C
Written by Ethan Benson
Portions based on show_of_path.sh written by Olaf Hering
-Copyright (C) 2000, 2001, 2002 Ethan Benson
+Copyright (C) 2000, 2001, 2002, 2003 Ethan Benson
Portions Copyright (C) 2000 Olaf Hering
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
## small tr replacment which handles a specific need of this script.
smalltr()
{
- case "$1" in
+ case "$1" in
a) echo 1 ;; b) echo 2 ;; c) echo 3 ;; d) echo 4 ;; e) echo 5 ;; f) echo 6 ;;
g) echo 7 ;; h) echo 8 ;; i) echo 9 ;; j) echo 10 ;; k) echo 11 ;; l) echo 12 ;;
m) echo 13 ;; n) echo 14 ;; o) echo 15 ;; p) echo 16 ;;
- 1) echo a ;; 2) echo b ;; 3) echo c ;; 4) echo d ;; 5) echo e ;;
+ 1) echo a ;; 2) echo b ;; 3) echo c ;; 4) echo d ;; 5) echo e ;;
6) echo f ;; 7) echo g ;; 8) echo h ;; 9) echo i ;; 10) echo j ;;
11) echo k ;; 12) echo l ;; 13) echo m ;; 14) echo n ;; 15) echo o ;;
16) echo p ;;
else
readlink()
{
- local SYMTARGET="$(v=`ls -l "$2" 2>/dev/null` ; echo ${v##*> })"
+ local SYMTARGET="$(v=`ls -l "$1" 2>/dev/null` ; echo ${v##*> })"
if [ -n "$SYMTARGET" ] ; then
echo "$SYMTARGET"
return 0
{
## see if system has scsi at all
if [ ! -f /proc/scsi/scsi ] ; then
+ local kver="$(uname -r)"
+ case "$kver" in
+ 2.5.*|2.6.*)
+ if [ -d /sys/bus/scsi/devices -a \
+ -n "$(ls /sys/bus/scsi/devices 2>/dev/null)" ] ; then
+ echo 1>&2 "$PRG: /proc/scsi/scsi does not exist"
+ echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_SCSI_PROC_FS=y"
+ return 1
+ fi
+ ;;
+ esac
echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
return 1
fi
DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVTYPE=$DEVTYPE"
+ ## get the device LUN.
+ DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
+ [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVLUN=$DEVLUN"
+
## get the device id.
DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVID=$DEVID"
+ ## get the device bus.
+ DEVBUS="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
+ [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVBUS=$DEVBUS"
+
## get the scsi host id.
DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVHOST=$DEVHOST"
- if [ "$DEVTYPE" = "Direct-Access" ] ; then
+ if [ "$DEVTYPE" = "Direct-Access" ] || [ "$DEVTYPE" = "Direct-Access-RBC" ] ; then
DEVCOUNT="$(($DEVCOUNT + 1))"
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVCOUNT=$DEVCOUNT"
if [ "$SUBDEV" = "$DEVCOUNT" ] ; then
DEVICE_HOST=$DEVHOST
+ DEVICE_BUS=$DEVBUS
DEVICE_ID=$DEVID
+ DEVICE_LUN=$DEVLUN
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
break
fi
return 0
}
+read_attr()
+{
+ local ATTR=$1
+ local START=$2
+ local OLDDIR=$(pwd)
+ local RET
+
+ cd -P "$START"
+ while [[ $PWD != "/" ]]; do
+ ls $ATTR > /dev/null 2>&1
+ if [[ $? -eq 0 ]]; then
+ RET=$(cat $ATTR)
+ cd $OLDDIR
+ echo "$RET"
+ return 0
+ fi
+ cd ..
+ done
+
+ cd $OLDDIR
+ echo 1>&2 "$PRG: Cannot find $RET for $DEVICE"
+ exit 1
+}
+
+read_dev_attr()
+{
+ local ATTR=$1
+ local DEVICE="$DEVICE_HOST:$DEVICE_BUS:$DEVICE_ID:$DEVICE_LUN"
+ local START="/sys/bus/scsi/devices/$DEVICE"
+
+ read_attr $ATTR $START
+}
+
+read_parent_attr()
+{
+ local ATTR=$1
+ local DEVICE="$DEVICE_HOST:$DEVICE_BUS:$DEVICE_ID:$DEVICE_LUN"
+ local START="/sys/bus/scsi/devices/$DEVICE/.."
+
+ read_attr $ATTR $START
+}
+
+get_vdisk_lun()
+{
+ local B C D
+ typeset -i B C D
+
+ B=$((0x$DEVICE_ID << 8))
+ C=$((0x$DEVICE_BUS << 5))
+ D=$((0x$DEVICE_LUN))
+
+ local vdiskno vdisk
+ typeset -i vdiskno
+ vdiskno=$((0x8000 | $B | $C | $D ))
+ vdisk=${vdiskno##-}
+
+ vdisk=$(printf "%x" $vdisk)
+ local extrazeroes="000000000000"
+ echo $vdisk$extrazeroes
+}
+
+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"
+}
+
+get_fc_scsilun()
+{
+ local L=$(echo "$DEVICE_LUN"|gawk '{$1=tolower($1);print}')
+ L=$(printf "%d" $L)
+
+ 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"
+}
+
+scsi_ofpath2()
+{
+ local DEVSPEC=$(read_parent_attr devspec)
+ local COMPAT=$(cat "/proc/device-tree$DEVSPEC/compatible")
+ local DEVICE_PATH="/sys/bus/scsi/devices/$DEVICE_HOST:$DEVICE_BUS:$DEVICE_ID:$DEVICE_LUN"
+
+ case "$COMPAT" in
+ IBM,v-scsi)
+ local vdisk=$(get_vdisk_lun)
+ if [[ $PARTITION = "" ]]; then
+ echo "$DEVSPEC/disk@$vdisk"
+ else
+ echo "$DEVSPEC/disk@$vdisk:$PARTITION"
+ fi
+ return 0
+ ;;
+ IBM,vfc-client)
+ local vfc_lun=$(get_fc_scsilun)
+ local wwpn=$(get_fc_wwpn "$DEVICE_PATH/../../fc_remote_ports*")
+ if [[ $DEVICE_LUN != "0" ]]; then
+ local vfc_lun=$(get_fc_scsilun)
+ echo "$DEVSPEC/disk@$wwpn,$vfc_lun"
+ else
+ echo "$DEVSPEC/disk@$wwpn"
+ fi
+ return 0
+ ;;
+ *)
+ ;;
+ esac
+
+ if [[ -d "/proc/device-tree$DEVSPEC/sas" ]]; then
+ local vendor_id=$(read_parent_attr vendor)
+ local sas_addr
+
+ if [[ $vendor_id = "0x1000" ]]; then
+ sas_addr=$(read_dev_attr sas_address)
+ sas_addr=${sas_addr##0x}
+ if [[ $DEVICE_LUN != "0" ]]; then
+ local LUN=$(int_to_scsilun $DEVICE_LUN)
+ echo "$DEVSPEC/sas/disk@$sas_addr,$LUN"
+ else
+ echo "$DEVSPEC/sas/disk@$sas_addr"
+ fi
+ return 0
+ fi
+
+ local fwtype="0"
+ if [[ -e /sys/class/scsi_host/host$DEVICE_HOST/fw_type ]]; then
+ fwtype=$(cat /sys/class/scsi_host/host$DEVICE_HOST/fw_type)
+ fi
+
+ if [[ $fwtype = "1" ]]; then
+ sas_addr=$(read_dev_attr device_id)
+ sas_addr=${sas_addr##0x}
+ if [[ $DEVICE_LUN != "0" ]]; then
+ local LUN=$(int_to_scsilun $DEVICE_LUN)
+ echo "$DEVSPEC/sas/disk@$sas_addr,$LUN"
+ else
+ echo "$DEVSPEC/sas/disk@$sas_addr"
+ fi
+ else
+ local B T L
+
+ B=$(echo "$DEVICE_BUS"|gawk '{$1=tolower($1);print}')
+ B=$(printf "%d" $B)
+ T=$(echo "$DEVICE_ID"|gawk '{$1=tolower($1);print}')
+ T=$(printf "%d" $T)
+ L=$(echo "$DEVICE_LUN"|gawk '{$1=tolower($1);print}')
+ L=$(printf "%d" $L)
+
+ sas_addr=$(( ($B << 16) | ($T << 8) | $L ))
+ if [[ $DEVICE_LUN != "0" ]]; then
+ printf "%s/sas/disk@%x,%x\n" $DEVSPEC $sas_addr $DEVICE_LUN
+ else
+ printf "%s/sas/disk@%x\n" $DEVSPEC $sas_addr
+ fi
+ fi
+ return 0
+ fi
+
+ echo 1>&2 "$PRG: Driver: $SCSI_DRIVER is not supported"
+ return 1
+}
+
## generic function that can find OF device paths for scsi devices,
## must be run after scsiinfo().
scsi_ofpath()
DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
;;
+ ata_k2|sata_svw)
+ #Not all G5 device trees have a compatible "k2-sata" node
+ #per channel use parent
+ HOST_LIST="$(for i in `find /proc/device-tree -name compatible ` ; do
+ lgrep "$i" "k2-s-ata" ; done | sort)"
+ DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
+ K2_DEVICE_ID=0
+ while [ "$DEVICE_PATH" = "" ] ; do
+ SCSI_HOSTNUMBER=`expr $SCSI_HOSTNUMBER - 1`
+ let "K2_DEVICE_ID += 1"
+ DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
+ done
+ echo "${DEVICE_PATH##*device-tree}/k2-sata@$K2_DEVICE_ID/disk@0:$PARTITION"
+ ;;
+ usb-storage)
+ HOST_LIST="$(for i in `find /proc/device-tree -name name | grep usb` ; do
+ lgrep "$i" "disk" ; done)"
+ DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
+ echo "${DEVICE_PATH##*device-tree}:$PARTITION"
+ ;;
+ sbp2|"")
+ # sbp-2 driver may not have a dir in /proc/scsi
+ HOST_LIST="$(for i in `find /proc/device-tree -name name` ; do
+ lgrep "$i" "sbp-2" ; done)"
+ if [ "$HOST_LIST" = "" ] ; then
+ scsi_ofpath2
+ else
+ if [ "$SCSI_HOSTNUMBER" = "" ] ; then
+ SCSI_HOSTNUMBER=1
+ fi
+ DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
+ echo "${DEVICE_PATH##*device-tree}/disk@0:$PARTITION"
+ fi
+ ;;
*)
echo 1>&2 "$PRG: Driver: $SCSI_DRIVER is not supported"
return 1
ide_ofpath()
{
if [ ! -L "/proc/ide/$DEVNODE" ] ; then
- echo 2>&1 "$PRG: /dev/$DEVNODE: Device not configured"
+ echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
return 1
fi
echo 1>&2 "$PRG: BUG: IDEBUS == NULL"
return 1
fi
- local OF1275IDE="/proc/ide/$IDEBUS/devspec"
+
+ case "$(uname -r)" in
+ 2.5.*|2.6.0*|2.6.1|2.6.1-*|2.6.2|2.6.2-*)
+ echo 1>&2 "$PRG: Linux kernel `uname -r` is not supported"
+ return 1
+ ;;
+ 2.6.*|2.7.*)
+ if ! (grep -q '.* .* sysfs ' /proc/mounts 2> /dev/null) ; then
+ echo 1>&2 "$PRG: sysfs must be mounted for ofpath to support this system"
+ return 1
+ fi
+ local SYS="$(m=`grep '.* .* sysfs ' /proc/mounts | head -n 1` ; echo `d=${m#* };echo ${d%% *}`)"
+ if [ -z "$SYS" -o ! -d "$SYS" ] ; then
+ echo 1>&2 "$PRG: Unable to determine sysfs mountpoint"
+ return 1
+ fi
+ local OF1275IDE="${SYS}/block/${DEVNODE}/device/../../devspec"
+ ;;
+ *)
+ local OF1275IDE="/proc/ide/$IDEBUS/devspec"
+ ;;
+ esac
if [ ! -f "$OF1275IDE" ] ; then
case "$(cat /proc/device-tree/model)" in
- "PowerMac3,6")
+ PowerMac3*|PowerMac4*|PowerMac5*|PowerMac6*|PowerMac7*|RackMac*)
local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
if [ -z "$CDROM" ] ; then
+ echo 1>&2 "$PRG: WARNING: Your kernel is too old for proper support, device may be innaccurate."
echo "ultra2:$PARTITION"
else
echo "cd:$PARTITION"
return 1
fi
+ if [ ! -f "/proc/ide/${IDEBUS}/channel" ] ; then
+ echo 1>&2 "$PRG: KERNEL BUG: /proc/ide/${IDEBUS}/channel does not exist"
+ return 1
+ fi
+
case "$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)" in
- ata)
- local CHANNEL=""
+ ide|ata)
+ local MASTER="/disk@0"
+ local SLAVE="/disk@1"
;;
- pci-ata)
- if [ ! -f "/proc/ide/${IDEBUS}/channel" ] ; then
- echo 1>&2 "$PRG: KERNEL BUG: /proc/ide/${IDEBUS}/channel does not exist"
- return 1
- fi
- local CHANNEL="/@$(cat /proc/ide/${IDEBUS}/channel)"
+ pci-ide|pci-ata)
+ local MASTER="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@0"
+ local SLAVE="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@1"
+ ;;
+ scsi) ## some lame controllers pretend they are scsi, hopefully all kludges are created equal.
+ local MASTER="/@$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 0))"
+ local SLAVE="/@$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 1))"
+ ;;
+ spi)
+ local MASTER="/disk@$(cat /proc/ide/${IDEBUS}/channel),0"
+ local SLAVE="/disk@$(cat /proc/ide/${IDEBUS}/channel),1"
;;
*)
- echo 2>&1 "$PRG: Unsupported IDE device type: \"$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)\""
+ echo 1>&2 "$PRG: Unsupported IDE device type: \"$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)\""
return 1
;;
esac
case "$DEVNODE" in
- hda|hdc|hde|hdg|hdi)
- echo "${DEVSPEC}${CHANNEL}/disk@0:$PARTITION"
+ hda|hdc|hde|hdg|hdi|hdk|hdm|hdo)
+ echo "${DEVSPEC}${MASTER}:$PARTITION"
return 0
;;
- hdb|hdd|hdf|hdh|hdj)
- echo "${DEVSPEC}${CHANNEL}/disk@1:$PARTITION"
+ hdb|hdd|hdf|hdh|hdj|hdl|hdn|hdp)
+ echo "${DEVSPEC}${SLAVE}:$PARTITION"
return 0
;;
*)
{
case "$DEVNODE" in
sd*)
- if ls -l /proc/device-tree | grep -q ^lr ; then
- true
- else
- echo 1>&2 "$PRG: /proc/device-tree is broken. Do not use BootX to boot, use yaboot."
- echo 1>&2 "$PRG: The yaboot HOWTO can be found here: http://www.alaska.net/~erbenson/doc"
- return 1
- fi
-
## use common scsiinfo function to get info we need.
scsiinfo || return 1
## now we have the data for /@$DEVID:$PARTITION
- ## find the actual OF path.
+ ## find the actual OF path.
scsi_ofpath || return 1
;;
hd*)
{
case "$DEVNODE" in
sd*)
- if ls -l /proc/device-tree | grep -q ^lr ; then
- true
- else
- echo 1>&2 "$PRG: /proc/device-tree is broken."
- return 1
- fi
## use common scsiinfo function to get info we need.
scsiinfo || return 1
## now we have the data for /@$DEVID:$PARTITION
- ## find the actual OF path.
+ ## find the actual OF path.
scsi_ofpath || return 1
;;
*)
local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE"
- if [ "$DEVTYPE" = "Direct-Access" ] ; then
+ if [ "$DEVTYPE" = "Direct-Access" ] || [ "$DEVTYPE" = "Direct-Access-RBC" ] ; then
## Lets find out some more information
## get the device id.
local DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
fi
## check for ppc, i think uname -m is safe for this...
-if [ `uname -m` != ppc ] ; then
+if [ `uname -m` != ppc -a `uname -m` != ppc64 ] ; then
echo 1>&2 "$PRG: This utility will only work on PowerPC hardware"
exit 1
fi
SUBARCH=OldWorld
elif (cat /proc/cpuinfo 2> /dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
SUBARCH=CHRP
+elif (cat /proc/cpuinfo 2>/dev/null | grep ^machine | grep -q 'CHRP Pegasos') ; then
+ SUBARCH=Pegasos
else
echo 1>&2 "$PRG: This machine is not yet supported"
exit 1
## use appropriate search for right sub arch.
case "$SUBARCH" in
- NewWorld)
+ # Pegasos OF seems to be NewWorld-ish enough to cope with this.
+ NewWorld|Pegasos)
newworld || exit 1
;;
OldWorld)