#! /bin/sh ############################################################################### ## ## ofpath: determine OpenFirmware path from unix device node ## Copyright (C) 2000, 2001, 2002, 2003 Ethan Benson ## ## Portions based on show_of_path.sh: ## ## Copyright (C) 2000 Olaf Hering ## ## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## ############################################################################### PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" PRG="${0##*/}" VERSION=1.0.7 DEBUG=0 export LC_COLLATE=C ## --version output. version() { echo \ "$PRG $VERSION Written by Ethan Benson Portions based on show_of_path.sh written by Olaf Hering 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." } ## --help output. usage() { echo \ "Usage: $PRG [OPTION]... FILE Find OpenFirmware device path from unix device node. --debug print boring junk only useful for debugging -h, --help display this help and exit -V, --version output version information and exit" } ## a small seq replacement, seq is not present on boot/rescue floppies. smallseq() { local v="$1" local n=1 echo 1 while [ "$v" -gt 1 ] ; do echo "$(($n + 1))" local n="$(($n + 1))" local v="$(($v - 1))" done return 0 } ## a kludge to replace wc -l, wc is not present on boot/rescue ## floppies. max file is 145 lines, 3 hosts * 16 devs each * 3 lines ## per device, + 1 "Attached Devices:" line. linecount() { if [ $# = 0 ] ; then local file="$(cat)" local v="$file" else local file="$(cat $1)" local v="$file" fi if [ -z "$file" ] ; then echo 0 return 0 fi ## use real wc if available if (command -v wc > /dev/null 2>&1) ; then if [ -x `command -v wc` ] ; then lines="$(echo "$file" | wc -l)" if [ $? = 0 ] ; then echo $lines unset lines return 0 fi fi fi while true ; do for i in `smallseq 145` ; do local b="$(echo "$file" | tail -n $i)" if [ "$v" = "$b" ] ; then echo "$i" break 2 fi done done return 0 } ## small tr replacment which handles a specific need of this script. smalltr() { local i a d t val out mod cur val="$1" out="0" d=$(printf "%d\n" \'${val:0:1}) if (( $d > 57 )) ; then # is a letter for ((i=0; i < ${#val}; i++)) ; do d=$(printf "%d\n" \'${val:$i:1}) a=$(($d - 96)) out=$(($out * 26)) out=$(($out + $a)) done else # is a number t=$val out="" while ((t != 0)) ; do mod=$(($t % 26)) t=$(($t / 26)) if (($mod == 0)) ; then cur="z" t=$(($t - 1)) else mod=$(($mod + 96)) cur=$(echo $mod | gawk '{printf "%c", $1}') fi out="$cur$out" done fi echo "$out" return 0 } ## replacment for grep -l which is not supported by busybox grep. ## echo $(cat..) hack needed because busybox grep barfs with `line too ## long' when fed /proc files. the for loop is needed since busybox ## grep seems to have somewhat broken regexp support. ## usage: lgrep filename regexp regexp ... lgrep() { local f="$1" shift for i in "$@" ; do echo "$(cat "$f")" | grep -q "$i" && echo "$f" && break done return 0 } ## if readlink is missing use a kludge if (command -v readlink > /dev/null 2>&1) ; then true else readlink() { local SYMTARGET="$(v=`ls -l "$1" 2>/dev/null` ; echo ${v##*> })" if [ -n "$SYMTARGET" ] ; then echo "$SYMTARGET" return 0 else return 1 fi } fi ## a function to print relevant scsi host path when there is more then ## one. this function also takes care of stripping off the trailing ## /compatible. printhost() { case "$1" in 1) echo "${2%/*}" ;; 2) echo "${3%/*}" ;; 3) echo "${4%/*}" ;; 4) echo "${5%/*}" ;; esac return 0 } ## this finds information we need on both newworld and oldworld macs. ## mainly what scsi host a disk is attached to. scsiinfo() { ## 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 ## first we have to figure out the SCSI ID, have to do that ## anyway [to] find the attached scsi disks = "Direct-Access" and ## stop at sda=1 sdb=2 or whatever count in 3 lines steps ## get last letter of device node, ie sda -> a SUBNODE=${DEVNODE##*sd} ## turn SUBNODE above into a number starting at 1, ie a -> 1 SUBDEV="$(smalltr $SUBNODE)" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SUBNODE=$SUBNODE SUBDEV=$SUBDEV" DEVCOUNT=0 ## copy scsi file into a variable removing "Attached Devices" ## which is the first line. this avoids a lot of ## [incmopatible] crap later, and improves readability. ## find number of lines once and recycle that number, to save ## some time (linecount is a bit slow). subtract one line ## to scrap Attached Devices: SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))" if [ "$SUBDEV" -gt "$(cat /proc/scsi/scsi | grep Direct-Access | linecount)" ] ; then echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured" return 1 fi PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)" for i in $(smallseq $(($SCSILINES / 3))) ; do ## put every scsi device into one single line DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVINFO=$DEVINFO" ## cut the type field, expect "Direct-Access" later. 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" ] || [ "$DEVTYPE" = "Direct-Access-RBC" ] ; then ls /sys/bus/scsi/devices/$DEVHOST:$DEVBUS:$DEVID:$DEVLUN/scsi_disk* > /dev/null 2>&1 if [ $? -eq 0 ] ; 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 fi fi done ## figure out what the scsi driver is, it is /proc/scsi/dirname. [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST" SCSI_DRIVER="$(x=`ls /proc/scsi/*/$DEVICE_HOST 2>/dev/null | cat` ; y=`echo ${x##*proc/scsi/}` ; echo ${y%%/*})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_DRIVER=$SCSI_DRIVER" ## figure out which host we found. SCSI_HOSTNUMBER="$(v=`ls /proc/scsi/$SCSI_DRIVER/* 2>/dev/null | cat | grep -n "$DEVICE_HOST\>"` ; echo ${v%%:*})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_HOSTNUMBER=$SCSI_HOSTNUMBER" 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 local fc=${DEVSPEC%@*} fc=${fc##/*/} if [[ -e /proc/device-tree$DEVSPEC/device_type ]]; then local devtype=$(cat /proc/device-tree$DEVSPEC/device_type); if [[ $devtype = "fcp" || $devtype = "scsi-fcp" ]]; then fc="fibre-channel"; fi fi if [[ $fc = "fibre-channel" ]]; then local wwpn=$(get_fc_wwpn "$DEVICE_PATH/../../fc_remote_ports*") local ofpath=$DEVSPEC if [[ ! -e /proc/device-tree$DEVSPEC/disk ]]; then for dir in `find /proc/device-tree$DEVSPEC -type d`; do if [[ -e $dir/disk ]]; then ofpath=${dir##/proc/device-tree} break; fi done fi ofpath=$(printf "%s/disk@%s" $ofpath $wwpn) if [[ $DEVICE_LUN != "0" ]]; then local fc_lun=$(get_fc_scsilun $DEVICE_LUN) ofpath=$(printf "%s,%s" $ofpath $fc_lun) fi echo "$ofpath" 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() { case "$SCSI_DRIVER" in aic7xxx) HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do lgrep "$i" "^ADPT" "^pci900[45]" "^pciclass,01000" ; done)" DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)" echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION" ;; sym53c8xx) HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do lgrep "$i" "^Symbios" "^pci1000" "^pciclass,01000" ; done)" DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)" echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION" ;; mesh) HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do lgrep "$i" "mesh" ; done)" 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 ;; esac return 0 } ide_ofpath() { if [ ! -L "/proc/ide/$DEVNODE" ] ; then echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured" return 1 fi local IDEBUS="$(v=`readlink /proc/ide/$DEVNODE` ; echo ${v%%/*} )" if [ -z "$IDEBUS" ] ; then echo 1>&2 "$PRG: BUG: IDEBUS == NULL" return 1 fi 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*|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" fi ;; *) local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)" if [ -z "$CDROM" ] ; then if [ "$DEVNODE" = hda ] ; then echo "hd:$PARTITION" else echo "ultra1:$PARTITION" fi else echo "cd:$PARTITION" fi ;; esac else local DEVSPEC="$(cat $OF1275IDE)" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVSPEC=$DEVSPEC" if [ -z "$DEVSPEC" ] ; then echo 1>&2 "$PRG: KERNEL BUG: $OF1275IDE exists, but is empty" 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 ide|ata) local MASTER="/disk@0" local SLAVE="/disk@1" ;; 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 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|hdk|hdm|hdo) echo "${DEVSPEC}${MASTER}:$PARTITION" return 0 ;; hdb|hdd|hdf|hdh|hdj|hdl|hdn|hdp) echo "${DEVSPEC}${SLAVE}:$PARTITION" return 0 ;; *) echo 1>&2 "$PRG: /dev/$DEVNODE is not supported" return 1 ;; esac fi } ## figure out the OpenFirmware device path for newworld macs. ## sd* scsi disks , hd* ide disks. newworld() { case "$DEVNODE" in sd*) ## 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. scsi_ofpath || return 1 ;; hd*) ide_ofpath || return 1 ;; *) echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported" return 1 ;; esac return 0 } oldworld() { ## for some reason 2.4 kernels put OF aliases in aliases@0/ instead of plain aliases/ if [ -d "/proc/device-tree/aliases" ] ; then local ALIASES="aliases" elif [ -d "/proc/device-tree/aliases@0" ] ; then local ALIASES="aliases@0" else echo 1>&2 "$PRG: Cannot find OpenFirmware aliases directory in /proc/device-tree/" return 1 fi local MODEL="$(cat /proc/device-tree/compatible)" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: Oldworld subarch: $MODEL" case "$MODEL" in AAPL,7300*|AAPL,7500*|AAPL,8500*|AAPL,9500*|AAPL,\?\?\?\?*) case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITION ;; 53c94) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; *) echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE" return 1 ;; esac ;; AAPL,e407*) case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; hda*) echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@0:$PARTITION ;; hdb*) echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@1:$PARTITION ;; hd*) echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported" ;; esac ;; AAPL,e826*) case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; hda*) echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@0:$PARTITION ;; hdb*) echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@1:$PARTITION ;; hd*) echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported" ;; esac ;; AAPL,Gossamer*|AAPL,PowerMac\ G3*) case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; hda*) echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@0:$PARTITION ;; hdb*) echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@1:$PARTITION ;; hdc*) echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@0:$PARTITION ;; hdd*) echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@1:$PARTITION ;; hd*) echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported" ;; esac ;; AAPL,PowerBook1998*) if [ -f /proc/device-tree/$ALIASES/ata0 ] ; then local ATA0=ata0 else local ATA0=ide0 fi if [ -f /proc/device-tree/$ALIASES/ata1 ] ; then local ATA1=ata1 else local ATA1=bay-ata1 fi case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; hda*) echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@0:$PARTITION ;; hdb*) echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@1:$PARTITION ;; hdc*) echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@0:$PARTITION ;; hdd*) echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@1:$PARTITION ;; *) echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE" return 1 ;; esac ;; AAPL,3400/2400*) case "$DEVNODE" in sd*) scsiinfo || return 1 case "$SCSI_DRIVER" in mesh) echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITON ;; 53c94) echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON ;; *) echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported" return 1 ;; esac ;; hda*) echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@0:$PARTITION ;; hdb*) echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@1:$PARTITION ;; hdc*) echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@0:$PARTITION ;; hdd*) echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@1:$PARTITION ;; hde*) echo $(cat /proc/device-tree/$ALIASES/ata2):$PARTITION ;; hdf*) echo $(cat /proc/device-tree/$ALIASES/ata3):$PARTITION ;; *) echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE" return 1 ;; esac ;; *) echo 1>&2 "$PRG: This machine is not supported: $MODEL" return 1 ;; esac return 0 } eth_ofpath() { read_attr devspec /sys/class/net/$DEVICE/device } hfi_ofpath() { 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 echo 1>&2 "$PRG: Unsupported device: $DEVICE" return 1 fi hfpath=${hfpath##/proc/device-tree} echo "$hfpath" } ## find OpenFirmware device path for IBM CHRP hardware (scsi only) chrp() { case "$DEVNODE" in sd*) ## 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. scsi_ofpath || return 1 ;; eth*) eth_ofpath || return 1 ;; hfi*) hfi_ofpath || return 1 ;; *) echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported" return 1 ;; esac return 0 } ## If we get lame devfs name, we need to make it foad ckdevfs() { case "$1" in /dev/ide/*|/dev/scsi/*|/dev/discs/*) return 0 ;; *) return 1 ;; esac } ## convert devfs names into normal short ones, written by Tom Rini. fixdevfs() { ## get partition number, if any local PARTNUM="${1##*[a-z]}" ## Find the bus type. local TYPE="$(v=${1#/dev/} ; echo ${v%/host*})" ## Find the host number. local HOST="$(v=${1#/dev/*/host} ; echo ${v%/bus*})" ## Find the bus number. local BUS="$(v=${1#/dev/*/bus} ; echo ${v%/tar*})" ## Find the target. local TARGET="$(v=${1#/dev/*/target} ; echo ${v%/lun*})" case "$TYPE" in ide) case "$HOST" in 0) case "$TARGET" in 0) local DEV=hda ;; 1) local DEV=hdb ;; esac ;; 1) case "$TARGET" in 0) local DEV=hdc ;; 1) local DEV=hdd ;; esac ;; *) echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs." return 1 esac local DEV="${DEV}${PARTNUM}" echo "/dev/$DEV" return 0 ;; scsi) local LUN="$(v=${1#/dev/*/lun} ; echo ${v%/*})" ## In this case, we need to figure out what number our device is local DEVCOUNT=0 ## copy scsi file into a variable removing "Attached Devices" ## which is the first line. this avoids a lot of ## [incmopatible] crap later, and improves readability. ## find number of lines once and recycle that number, to save ## some time (linecount is a bit slow). subtract one line ## to scrap Attached Devices: local SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))" local PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)" for i in $(smallseq $(($SCSILINES / 3))) ; do ## put every scsi device into one single line local DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVINFO=$DEVINFO" ## cut the type field, expect "Direct-Access" later. local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE" 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})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVID=$DEVID" ## get the device lun. local DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVLUN=$DEVLUN" ## get the device channel. local DEVCHAN="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCHAN=$DEVCHAN" ## get the scsi host id. local DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVHOST=$DEVHOST" local DEVCOUNT="$(($DEVCOUNT + 1))" [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCOUNT=$DEVCOUNT" if [ "$DEVHOST" = "$HOST" -a "$DEVCHAN" = "$BUS" -a \ "$DEVID" = "$TARGET" -a "$DEVLUN" = "$LUN" ] ; then local DEV="sd$(smalltr $DEVCOUNT)${PARTNUM}" echo "/dev/$DEV" return 0 fi fi done echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs." return 1 ;; *) echo 1>&2 "$PRG: Unknown bus $TYPE" return 1 ;; esac ## we should never get here return 1 } ## make sure that find, head and tail can be found. otherwise the ## script will silently give bogus paths. these are the only /usr/* ## utilities this script depends on. checkutils() { if command -v find > /dev/null 2>&1 ; then [ -x `command -v find` ] || FAIL=1 ; else FAIL=1 ; fi if command -v head > /dev/null 2>&1 ; then [ -x `command -v head` ] || FAIL=1 ; else FAIL=1 ; fi if command -v tail > /dev/null 2>&1 ; then [ -x `command -v tail` ] || FAIL=1 ; else FAIL=1 ; fi if [ "$FAIL" = 1 ] ; then echo 1>&2 "$PRG: \`find', \`head', or \`tail' could not be found, aborting." return 1 else return 0 fi } ## parse command line switches. if [ $# != 0 ] ; then while true ; do case "$1" in -V|--version) version exit 0 ;; -h|--help) usage exit 0 ;; --debug) DEBUG=1 shift ;; -*) echo 1>&2 "$PRG: unrecognized option \`$1'" echo 1>&2 "$PRG: Try \`$PRG --help' for more information." exit 1 ;; "") echo 1>&2 "$PRG: You must specify a filename" echo 1>&2 "Try \`$PRG --help' for more information." exit 1 ;; *) device="$1" break ;; esac done else echo 1>&2 "$PRG: You must specify a /dev device" echo 1>&2 "Try \`$PRG --help' for more information." exit 1 fi ## check that we are running on a GNU/Linux system, OSX/BSD does not ## have the same /proc stuff if [ `uname -s` != Linux ] ; then echo 1>&2 "$PRG: This utility will only work with GNU/Linux" exit 1 fi ## check for ppc, i think uname -m is safe for this... if [ `uname -m` != ppc -a `uname -m` != ppc64 ] ; then echo 1>&2 "$PRG: This utility will only work on PowerPC hardware" exit 1 fi ## ofpath cannot live without procfs if [ ! -f /proc/uptime ] ; then echo 1>&2 "$PRG: This utility requires the /proc filesystem" exit 1 fi ## check for retarded devfs names and tell them to foad. if ckdevfs "$device" ; then device="$(fixdevfs $device)" || exit 1 fi ## check for newworld mac. use cat hack due to /proc wierdness. if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = NewWorld ] ; then SUBARCH=NewWorld elif [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = OldWorld ] ; then SUBARCH=OldWorld elif (cat /proc/cpuinfo 2>/dev/null | grep ^motherboard | grep -q AAPL) ; then 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 fi ## make sure /proc/device-tree exists if [ ! -d /proc/device-tree ] ; then echo 1>&2 "$PRG: /proc/device-tree does not exist" echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_PROC_DEVICETREE=y" exit 1 fi ## make sure we have what we need. checkutils || exit 1 ## get the base device node and scrap /dev/ ie /dev/hda2 -> hda DEVICE="${device##*/}" DEVNODE="${DEVICE%%[0-9]*}" PARTITION="${DEVICE##*[a-z]}" ## use appropriate search for right sub arch. case "$SUBARCH" in # Pegasos OF seems to be NewWorld-ish enough to cope with this. NewWorld|Pegasos) newworld || exit 1 ;; OldWorld) oldworld || exit 1 ;; CHRP) chrp || exit 1 ;; esac exit 0