Add PowerMac G5 SATA support to ofpath
[yaboot.git] / ybin / ofpath
1 #! /bin/sh
2
3 ###############################################################################
4 ##
5 ## ofpath: determine OpenFirmware path from unix device node
6 ## Copyright (C) 2000, 2001, 2002, 2003 Ethan Benson
7 ##
8 ## Portions based on show_of_path.sh:
9 ##
10 ## Copyright (C) 2000 Olaf Hering <olh@suse.de>
11 ## 
12 ## This program is free software; you can redistribute it and/or
13 ## modify it under the terms of the GNU General Public License
14 ## as published by the Free Software Foundation; either version 2
15 ## of the License, or (at your option) any later version.
16 ##
17 ## This program is distributed in the hope that it will be useful,
18 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ## GNU General Public License for more details.
21 ##
22 ## You should have received a copy of the GNU General Public License
23 ## along with this program; if not, write to the Free Software
24 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25 ##
26 ###############################################################################
27
28 PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
29 PRG="${0##*/}"
30 VERSION=1.0.5-UNRELEASED_UNSUPPORTED
31 DEBUG=0
32 export LC_COLLATE=C
33
34 ## --version output.
35 version()
36 {
37 echo \
38 "$PRG $VERSION
39 Written by Ethan Benson
40 Portions based on show_of_path.sh written by Olaf Hering
41
42 Copyright (C) 2000, 2001, 2002, 2003 Ethan Benson
43 Portions Copyright (C) 2000 Olaf Hering
44 This is free software; see the source for copying conditions.  There is NO
45 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
46 }
47
48 ## --help output.
49 usage()
50 {
51 echo \
52 "Usage: $PRG [OPTION]... FILE
53 Find OpenFirmware device path from unix device node.
54
55       --debug                print boring junk only useful for debugging
56   -h, --help                 display this help and exit
57   -V, --version              output version information and exit"
58 }
59
60 ## a small seq replacement, seq is not present on boot/rescue floppies.
61 smallseq()
62 {
63     local v="$1"
64     local n=1
65     echo 1
66     while [ "$v" -gt 1 ] ; do
67         echo "$(($n + 1))"
68         local n="$(($n + 1))"
69         local v="$(($v - 1))"
70     done
71     return 0
72 }
73
74 ## a kludge to replace wc -l, wc is not present on boot/rescue
75 ## floppies. max file is 145 lines, 3 hosts * 16 devs each * 3 lines
76 ## per device, + 1 "Attached Devices:" line.
77 linecount()
78 {
79     if [ $# = 0 ] ; then
80         local file="$(cat)"
81         local v="$file"
82     else
83         local file="$(cat $1)"
84         local v="$file"
85     fi
86
87     if [ -z "$file" ] ; then
88         echo 0
89         return 0
90     fi
91
92     ## use real wc if available
93     if (command -v wc > /dev/null 2>&1) ; then
94         if [ -x `command -v wc` ] ; then
95             lines="$(echo "$file" | wc -l)"
96             if [ $? = 0 ] ; then
97                 echo $lines
98                 unset lines
99                 return 0
100             fi
101         fi
102     fi
103
104     while true ; do
105         for i in `smallseq 145` ; do
106             local b="$(echo "$file" | tail -n $i)"
107             if [ "$v" = "$b" ] ; then
108                 echo "$i"
109                 break 2
110             fi
111         done
112     done
113     return 0
114 }
115
116 ## small tr replacment which handles a specific need of this script.
117 smalltr()
118 {
119     case "$1" in 
120         a) echo 1 ;; b) echo 2 ;; c) echo 3 ;; d) echo 4 ;; e) echo 5 ;; f) echo 6 ;;
121         g) echo 7 ;; h) echo 8 ;; i) echo 9 ;; j) echo 10 ;; k) echo 11 ;; l) echo 12 ;;
122         m) echo 13 ;; n) echo 14 ;; o) echo 15 ;; p) echo 16 ;;
123         1) echo a ;; 2) echo b ;; 3) echo c ;; 4) echo d ;; 5) echo e ;; 
124         6) echo f ;; 7) echo g ;; 8) echo h ;; 9) echo i ;; 10) echo j ;;
125         11) echo k ;; 12) echo l ;; 13) echo m ;; 14) echo n ;; 15) echo o ;;
126         16) echo p ;;
127     esac
128     return 0
129 }
130
131 ## replacment for grep -l which is not supported by busybox grep.
132 ## echo $(cat..) hack needed because busybox grep barfs with `line too
133 ## long' when fed /proc files.  the for loop is needed since busybox
134 ## grep seems to have somewhat broken regexp support.
135 ## usage: lgrep filename regexp regexp ...
136 lgrep()
137 {
138     local f="$1"
139     shift
140     for i in "$@" ; do
141         echo "$(cat "$f")" | grep -q "$i" && echo "$f" && break
142     done
143     return 0
144 }
145
146 ## if readlink is missing use a kludge
147 if (command -v readlink > /dev/null 2>&1) ; then
148     true
149 else
150     readlink()
151     {
152         local SYMTARGET="$(v=`ls -l "$1" 2>/dev/null` ; echo ${v##*> })"
153         if [ -n "$SYMTARGET" ] ; then
154             echo "$SYMTARGET"
155             return 0
156         else
157             return 1
158         fi
159     }
160 fi
161
162 ## a function to print relevant scsi host path when there is more then
163 ## one.  this function also takes care of stripping off the trailing
164 ## /compatible.
165 printhost()
166 {
167     case "$1" in
168         1)
169         echo "${2%/*}"
170         ;;
171         2)
172         echo "${3%/*}"
173         ;;
174         3)
175         echo "${4%/*}"
176         ;;
177         4)
178         echo "${5%/*}"
179         ;;
180     esac
181     return 0
182 }
183
184 ## this finds information we need on both newworld and oldworld macs.
185 ## mainly what scsi host a disk is attached to.
186 scsiinfo()
187 {
188     ## see if system has scsi at all
189     if [ ! -f /proc/scsi/scsi ] ; then
190         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
191         return 1
192     fi
193
194     ## first we have to figure out the SCSI ID, have to do that
195     ## anyway [to] find the attached scsi disks = "Direct-Access" and
196     ## stop at sda=1 sdb=2 or whatever count in 3 lines steps
197
198     ## get last letter of device node, ie sda -> a
199     SUBNODE=${DEVNODE##*sd}
200
201     ## turn SUBNODE above into a number starting at 1, ie a -> 1
202     SUBDEV="$(smalltr $SUBNODE)"
203     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SUBNODE=$SUBNODE SUBDEV=$SUBDEV"
204
205     DEVCOUNT=0
206
207     ## copy scsi file into a variable removing "Attached Devices"
208     ## which is the first line. this avoids a lot of
209     ## [incmopatible] crap later, and improves readability.
210
211     ## find number of lines once and recycle that number, to save
212     ## some time (linecount is a bit slow). subtract one line
213     ## to scrap Attached Devices:
214
215     SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
216
217     if [ "$SUBDEV" -gt "$(cat /proc/scsi/scsi | grep Direct-Access | linecount)" ] ; then
218         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
219         return 1
220     fi
221
222     PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
223
224     for i in $(smallseq $(($SCSILINES / 3))) ; do
225
226         ## put every scsi device into one single line
227         DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
228         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVINFO=$DEVINFO"
229
230         ## cut the type field, expect "Direct-Access" later.
231         DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
232         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVTYPE=$DEVTYPE"
233
234         ## get the device id.
235         DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
236         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVID=$DEVID"
237
238         ## get the scsi host id.
239         DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
240         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVHOST=$DEVHOST"
241
242         if [ "$DEVTYPE" = "Direct-Access" ] ; then
243             DEVCOUNT="$(($DEVCOUNT + 1))"
244             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVCOUNT=$DEVCOUNT"
245             if [ "$SUBDEV" = "$DEVCOUNT" ] ; then
246                 DEVICE_HOST=$DEVHOST
247                 DEVICE_ID=$DEVID
248                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
249                 break
250             fi
251         fi
252     done
253
254     ## figure out what the scsi driver is, it is /proc/scsi/dirname.
255     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
256     SCSI_DRIVER="$(x=`ls /proc/scsi/*/$DEVICE_HOST 2>/dev/null | cat` ; y=`echo ${x##*proc/scsi/}` ; echo ${y%%/*})"
257     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_DRIVER=$SCSI_DRIVER"
258
259     ## figure out which host we found.
260     SCSI_HOSTNUMBER="$(v=`ls /proc/scsi/$SCSI_DRIVER/* 2>/dev/null | cat | grep -n "$DEVICE_HOST\>"` ; echo ${v%%:*})"
261     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_HOSTNUMBER=$SCSI_HOSTNUMBER"
262
263     return 0
264 }
265
266 ## generic function that can find OF device paths for scsi devices,
267 ## must be run after scsiinfo().
268 scsi_ofpath()
269 {
270     case "$SCSI_DRIVER" in
271         aic7xxx)
272             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
273                         lgrep "$i" "^ADPT" "^pci900[45]" "^pciclass,01000" ; done)"
274             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
275             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
276             ;;
277         sym53c8xx)
278             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
279                         lgrep "$i" "^Symbios" "^pci1000" "^pciclass,01000" ; done)"
280             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
281             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
282             ;;
283         mesh)
284             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
285                         lgrep "$i" "mesh" ; done)"
286             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
287             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
288             ;;
289         ata_k2)
290             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
291                         lgrep "$i" "k2-s-ata" ; done)"
292             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
293             echo "${DEVICE_PATH##*device-tree}/k2-sata@$DEVICE_ID/disk@0:$PARTITION"
294             ;;
295         *)
296             echo 1>&2 "$PRG: Driver: $SCSI_DRIVER is not supported"
297             return 1
298             ;;
299     esac
300     return 0
301 }
302
303 ide_ofpath()
304 {
305     if [ ! -L "/proc/ide/$DEVNODE" ] ; then
306         echo 2>&1 "$PRG: /dev/$DEVNODE: Device not configured"
307         return 1
308     fi
309
310     local IDEBUS="$(v=`readlink /proc/ide/$DEVNODE` ; echo ${v%%/*} )"
311     if [ -z "$IDEBUS" ] ; then
312         echo 1>&2 "$PRG: BUG: IDEBUS == NULL"
313         return 1
314     fi
315     local OF1275IDE="/proc/ide/$IDEBUS/devspec"
316
317     if [ ! -f "$OF1275IDE" ] ; then
318         case "$(cat /proc/device-tree/model)" in
319             "PowerMac3,6")
320                 local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
321                 if [ -z "$CDROM" ] ; then
322                     echo 1>&2 "$PRG: WARNING: Your kernel is too old for proper support, device may be innaccurate."
323                     echo "ultra2:$PARTITION"
324                 else
325                     echo "cd:$PARTITION"
326                 fi
327                 ;;
328             *)
329                 local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
330                 if [ -z "$CDROM" ] ; then
331                     if [ "$DEVNODE" = hda ] ; then
332                         echo "hd:$PARTITION"
333                     else
334                         echo "ultra1:$PARTITION"
335                     fi
336                 else
337                     echo "cd:$PARTITION"
338                 fi
339                 ;;
340         esac
341     else
342         local DEVSPEC="$(cat $OF1275IDE)"
343         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVSPEC=$DEVSPEC"
344         if [ -z "$DEVSPEC" ] ; then
345             echo 1>&2 "$PRG: KERNEL BUG: $OF1275IDE exists, but is empty"
346             return 1
347         fi
348
349         if [ ! -f "/proc/ide/${IDEBUS}/channel" ] ; then
350             echo 1>&2 "$PRG: KERNEL BUG: /proc/ide/${IDEBUS}/channel does not exist"
351             return 1
352         fi
353
354         case "$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)" in
355             ide|ata)
356                 local MASTER="/disk@0"
357                 local SLAVE="/disk@1"
358                 ;;
359             pci-ide|pci-ata)
360                 local MASTER="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@0"
361                 local SLAVE="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@1"
362                 ;;
363             scsi) ## some lame controllers pretend they are scsi, hopefully all kludges are created equal.
364                 local MASTER="/$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 0)),0"
365                 local SLAVE="/$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 1)),0"
366                 ;;
367             *)
368                 echo 2>&1 "$PRG: Unsupported IDE device type: \"$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)\""
369                 return 1
370                 ;;
371         esac
372
373         case "$DEVNODE" in
374             hda|hdc|hde|hdg|hdi|hdk|hdm|hdo)
375                 echo "${DEVSPEC}${MASTER}:$PARTITION"
376                 return 0
377                 ;;
378             hdb|hdd|hdf|hdh|hdj|hdl|hdn|hdp)
379                 echo "${DEVSPEC}${SLAVE}:$PARTITION"
380                 return 0
381                 ;;
382             *)
383                 echo 1>&2 "$PRG: /dev/$DEVNODE is not supported"
384                 return 1
385                 ;;
386         esac
387     fi
388 }
389
390 ## figure out the OpenFirmware device path for newworld macs.
391 ## sd* scsi disks , hd* ide disks.
392 newworld()
393 {
394     case "$DEVNODE" in
395         sd*)
396             if ls -l /proc/device-tree | grep -q ^lr ; then
397                 true
398             else
399                 echo 1>&2 "$PRG: /proc/device-tree is broken.  Do not use BootX to boot, use yaboot."
400                 echo 1>&2 "$PRG: The yaboot HOWTO can be found here: http://www.alaska.net/~erbenson/doc"
401                 return 1
402             fi
403
404             ## use common scsiinfo function to get info we need.
405             scsiinfo || return 1
406
407             ## now we have the data for /@$DEVID:$PARTITION
408             ## find the actual OF path. 
409             scsi_ofpath || return 1
410             ;;
411         hd*)
412             ide_ofpath || return 1
413             ;;
414         *)
415             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
416             return 1
417             ;;
418     esac
419     return 0
420 }
421
422 oldworld()
423 {
424     ## for some reason 2.4 kernels put OF aliases in aliases@0/ instead of plain aliases/
425     if [ -d "/proc/device-tree/aliases" ] ; then
426         local ALIASES="aliases"
427     elif [ -d "/proc/device-tree/aliases@0" ] ; then
428         local ALIASES="aliases@0"
429     else
430         echo 1>&2 "$PRG: Cannot find OpenFirmware aliases directory in /proc/device-tree/"
431         return 1
432     fi
433
434     local MODEL="$(cat /proc/device-tree/compatible)"
435     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: Oldworld subarch: $MODEL"
436
437     case "$MODEL" in
438         AAPL,7300*|AAPL,7500*|AAPL,8500*|AAPL,9500*|AAPL,\?\?\?\?*)
439             case "$DEVNODE" in
440                 sd*)
441                 scsiinfo || return 1
442                 case "$SCSI_DRIVER" in
443                     mesh)
444                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITION
445                     ;;
446                     53c94)
447                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
448                     ;;
449                     *)
450                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
451                     return 1
452                     ;;
453                 esac
454                 ;;
455                 *)
456                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
457                 return 1
458                 ;;
459             esac
460             ;;
461         AAPL,e407*)
462             case "$DEVNODE" in
463                 sd*)
464                 scsiinfo || return 1
465                 case "$SCSI_DRIVER" in
466                     mesh)
467                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
468                     ;;
469                     *)
470                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
471                     return 1
472                     ;;
473                 esac
474                 ;;
475                 hda*)
476                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@0:$PARTITION
477                 ;;
478                 hdb*)
479                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@1:$PARTITION
480                 ;;
481                 hd*)
482                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
483                 ;;
484             esac
485             ;;
486         AAPL,e826*)
487             case "$DEVNODE" in
488                 sd*)
489                 scsiinfo || return 1
490                 case "$SCSI_DRIVER" in
491                     mesh)
492                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
493                     ;;
494                     *)
495                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
496                     return 1
497                     ;;
498                 esac
499                 ;;
500                 hda*)
501                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@0:$PARTITION
502                 ;;
503                 hdb*)
504                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@1:$PARTITION
505                 ;;
506                 hd*)
507                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
508                 ;;
509             esac
510             ;;
511         AAPL,Gossamer*|AAPL,PowerMac\ G3*)
512             case "$DEVNODE" in
513                 sd*)
514                 scsiinfo || return 1
515                 case "$SCSI_DRIVER" in
516                     mesh)
517                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
518                     ;;
519                     *)
520                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
521                     return 1
522                     ;;
523                 esac
524                 ;;
525                 hda*)
526                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@0:$PARTITION
527                 ;;
528                 hdb*)
529                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@1:$PARTITION
530                 ;;
531                 hdc*)
532                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@0:$PARTITION
533                 ;;
534                 hdd*)
535                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@1:$PARTITION
536                 ;;
537                 hd*)
538                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
539                 ;;
540             esac
541             ;;
542         AAPL,PowerBook1998*)
543             if [ -f  /proc/device-tree/$ALIASES/ata0 ] ; then
544                 local ATA0=ata0
545             else
546                 local ATA0=ide0
547             fi
548             if [ -f  /proc/device-tree/$ALIASES/ata1 ] ; then
549                 local ATA1=ata1
550             else
551                 local ATA1=bay-ata1
552             fi
553             case "$DEVNODE" in
554                 sd*)
555                 scsiinfo || return 1
556                 case "$SCSI_DRIVER" in
557                     mesh)
558                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
559                     ;;
560                     *)
561                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
562                     return 1
563                     ;;
564                 esac
565                 ;;
566                 hda*)
567                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@0:$PARTITION
568                 ;;
569                 hdb*)
570                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@1:$PARTITION
571                 ;;
572                 hdc*)
573                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@0:$PARTITION
574                 ;;
575                 hdd*)
576                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@1:$PARTITION
577                 ;;
578                 *)
579                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
580                 return 1
581                 ;;
582             esac
583             ;;
584         AAPL,3400/2400*)
585             case "$DEVNODE" in
586                 sd*)
587                 scsiinfo || return 1
588                 case "$SCSI_DRIVER" in
589                     mesh)
590                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITON
591                     ;;
592                     53c94)
593                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
594                     ;;
595                     *)
596                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
597                     return 1
598                     ;;
599                 esac
600                 ;;
601                 hda*)
602                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@0:$PARTITION
603                 ;;
604                 hdb*)
605                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@1:$PARTITION
606                 ;;
607                 hdc*)
608                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@0:$PARTITION
609                 ;;
610                 hdd*)
611                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@1:$PARTITION
612                 ;;
613                 hde*)
614                 echo $(cat /proc/device-tree/$ALIASES/ata2):$PARTITION
615                 ;;
616                 hdf*)
617                 echo $(cat /proc/device-tree/$ALIASES/ata3):$PARTITION
618                 ;;
619                 *)
620                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
621                 return 1
622                 ;;
623             esac
624             ;;
625         *)
626             echo 1>&2 "$PRG: This machine is not supported: $MODEL"
627             return 1
628             ;;
629     esac
630     return 0
631 }
632
633 ## find OpenFirmware device path for IBM CHRP hardware (scsi only)
634 chrp()
635 {
636     case "$DEVNODE" in
637         sd*)
638             if ls -l /proc/device-tree | grep -q ^lr ; then
639                 true
640             else
641                 echo 1>&2 "$PRG: /proc/device-tree is broken."
642                 return 1
643             fi
644
645             ## use common scsiinfo function to get info we need.
646             scsiinfo || return 1
647
648             ## now we have the data for /@$DEVID:$PARTITION
649             ## find the actual OF path. 
650             scsi_ofpath || return 1
651             ;;
652         *)
653             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
654             return 1
655             ;;
656     esac
657     return 0
658 }
659
660 ## If we get lame devfs name, we need to make it foad
661 ckdevfs()
662 {
663     case "$1" in
664         /dev/ide/*|/dev/scsi/*|/dev/discs/*)
665         return 0
666         ;;
667         *)
668         return 1
669         ;;
670     esac
671 }
672
673 ## convert devfs names into normal short ones, written by Tom Rini.
674 fixdevfs()
675 {
676     ## get partition number, if any
677     local PARTNUM="${1##*[a-z]}"
678     ## Find the bus type.
679     local TYPE="$(v=${1#/dev/} ; echo ${v%/host*})"
680     ## Find the host number.
681     local HOST="$(v=${1#/dev/*/host} ; echo ${v%/bus*})"
682     ## Find the bus number.
683     local BUS="$(v=${1#/dev/*/bus} ; echo ${v%/tar*})"
684     ## Find the target.
685     local TARGET="$(v=${1#/dev/*/target} ; echo ${v%/lun*})"
686
687     case "$TYPE" in
688         ide)
689         case "$HOST" in
690             0)
691             case "$TARGET" in
692                 0)
693                 local DEV=hda
694                 ;;
695                 1)
696                 local DEV=hdb
697                 ;;
698             esac
699             ;;
700             1)
701             case "$TARGET" in
702                 0)
703                 local DEV=hdc
704                 ;;
705                 1)
706                 local DEV=hdd
707                 ;;
708             esac
709             ;;
710             *)
711                 echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
712                 return 1
713         esac
714         local DEV="${DEV}${PARTNUM}"
715         echo "/dev/$DEV"
716         return 0
717         ;;
718         scsi)
719         local LUN="$(v=${1#/dev/*/lun} ; echo ${v%/*})"
720
721         ## In this case, we need to figure out what number our device is
722         local DEVCOUNT=0
723
724         ## copy scsi file into a variable removing "Attached Devices"
725         ## which is the first line. this avoids a lot of
726         ## [incmopatible] crap later, and improves readability.
727
728         ## find number of lines once and recycle that number, to save
729         ## some time (linecount is a bit slow). subtract one line
730         ## to scrap Attached Devices:
731
732         local SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
733         local PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
734
735         for i in $(smallseq $(($SCSILINES / 3))) ; do
736
737             ## put every scsi device into one single line
738             local DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
739             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVINFO=$DEVINFO"
740
741             ## cut the type field, expect "Direct-Access" later.
742             local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
743             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE"
744
745             if [ "$DEVTYPE" = "Direct-Access" ] ; then
746                 ## Lets find out some more information
747                 ## get the device id.
748                 local DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
749                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVID=$DEVID"
750
751                 ## get the device lun.
752                 local DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
753                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVLUN=$DEVLUN"
754
755                 ## get the device channel.
756                 local DEVCHAN="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
757                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCHAN=$DEVCHAN"
758
759                 ## get the scsi host id.
760                 local DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
761                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVHOST=$DEVHOST"
762
763                 local DEVCOUNT="$(($DEVCOUNT + 1))"
764                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCOUNT=$DEVCOUNT"
765                 if [ "$DEVHOST" = "$HOST" -a "$DEVCHAN" = "$BUS" -a \
766                     "$DEVID" = "$TARGET" -a "$DEVLUN" = "$LUN" ] ; then
767                     local DEV="sd$(smalltr $DEVCOUNT)${PARTNUM}"
768                     echo "/dev/$DEV"
769                     return 0
770                 fi
771             fi
772         done
773         echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
774         return 1
775         ;;
776         *)
777         echo 1>&2 "$PRG: Unknown bus $TYPE"
778         return 1
779         ;;
780     esac
781     ## we should never get here
782     return 1
783 }
784
785 ## make sure that find, head and tail can be found.  otherwise the
786 ## script will silently give bogus paths.  these are the only /usr/*
787 ## utilities this script depends on.
788 checkutils()
789 {
790     if command -v find > /dev/null 2>&1 ; then
791         [ -x `command -v find` ] || FAIL=1 ; else FAIL=1 ; fi
792     if command -v head > /dev/null 2>&1 ; then
793         [ -x `command -v head` ] || FAIL=1 ; else FAIL=1 ; fi
794     if command -v tail > /dev/null 2>&1 ; then
795         [ -x `command -v tail` ] || FAIL=1 ; else FAIL=1 ; fi
796
797     if [ "$FAIL" = 1 ] ; then
798         echo 1>&2 "$PRG: \`find', \`head', or \`tail' could not be found, aborting."
799         return 1
800     else
801         return 0
802     fi
803 }
804
805 ## parse command line switches.
806 if [ $# != 0 ] ; then
807     while true ; do
808         case "$1" in
809             -V|--version)
810                 version
811                 exit 0
812                 ;;
813             -h|--help)
814                 usage
815                 exit 0
816                 ;;
817             --debug)
818                 DEBUG=1
819                 shift
820                 ;;
821             -*)
822                 echo 1>&2 "$PRG: unrecognized option \`$1'"
823                 echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
824                 exit 1
825                 ;;
826             "")
827                 echo 1>&2 "$PRG: You must specify a filename"
828                 echo 1>&2 "Try \`$PRG --help' for more information."
829                 exit 1
830                 ;;
831             *)
832                 device="$1"
833                 break
834                 ;;
835         esac
836     done
837 else
838     echo 1>&2 "$PRG: You must specify a /dev device"
839     echo 1>&2 "Try \`$PRG --help' for more information."
840     exit 1
841 fi
842
843 ## check that FILE is a block device and exists.
844 if [ ! -e "$device" ] ; then
845     echo 1>&2 "$PRG: $device: No such file or directory"
846     exit 1
847 elif [ ! -b "$device" ] ; then
848     echo 1>&2 "$PRG: $device is not a block device"
849     exit 1
850 fi
851
852 ## check that we are running on a GNU/Linux system, OSX/BSD does not
853 ## have the same /proc stuff
854 if [ `uname -s` != Linux ] ; then
855     echo 1>&2 "$PRG: This utility will only work with GNU/Linux"
856     exit 1
857 fi
858
859 ## check for ppc, i think uname -m is safe for this...
860 if [ `uname -m` != ppc ] ; then
861     echo 1>&2 "$PRG: This utility will only work on PowerPC hardware"
862     exit 1
863 fi
864
865 ## ofpath cannot live without procfs
866 if [ ! -f /proc/uptime ] ; then
867     echo 1>&2 "$PRG: This utility requires the /proc filesystem"
868     exit 1
869 fi
870
871 ## check for retarded devfs names and tell them to foad.
872 if ckdevfs "$device" ; then
873     device="$(fixdevfs $device)" || exit 1
874 fi
875
876 ## check for newworld mac. use cat hack due to /proc wierdness.
877 if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = NewWorld ] ; then
878     SUBARCH=NewWorld
879 elif [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = OldWorld ] ; then
880     SUBARCH=OldWorld
881 elif (cat /proc/cpuinfo 2>/dev/null | grep ^motherboard | grep -q AAPL) ; then
882     SUBARCH=OldWorld
883 elif (cat /proc/cpuinfo 2> /dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
884     SUBARCH=CHRP
885 else
886     echo 1>&2 "$PRG: This machine is not yet supported"
887     exit 1
888 fi
889
890 ## make sure /proc/device-tree exists
891 if [ ! -d /proc/device-tree ] ; then
892     echo 1>&2 "$PRG: /proc/device-tree does not exist"
893     echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_PROC_DEVICETREE=y"
894     exit 1
895 fi
896
897 ## make sure we have what we need.
898 checkutils || exit 1
899
900 ## get the base device node and scrap /dev/ ie /dev/hda2 -> hda
901 DEVICE="${device##*/}"
902 DEVNODE="${DEVICE%%[0-9]*}"
903 PARTITION="${DEVICE##*[a-z]}"
904
905 ## use appropriate search for right sub arch.
906 case "$SUBARCH" in
907     NewWorld)
908         newworld || exit 1
909         ;;
910     OldWorld)
911         oldworld || exit 1
912         ;;
913     CHRP)
914         chrp || exit 1
915         ;;
916 esac
917
918 exit 0