chiark / gitweb /
path_id: add iscsi support
[elogind.git] / extras / path_id / path_id.sh
1 #!/bin/sh
2
3 # provide the shortest possible unique hardware path to a device
4 # for the Linux Persistent Device Naming scheme
5 #
6 # Copyright (C) 2005-2006 SUSE Linux Products GmbH
7 # Author:
8 #       Hannes Reinecke <hare@suse.de>
9 #
10 #       This program is free software; you can redistribute it and/or modify it
11 #       under the terms of the GNU General Public License as published by the
12 #       Free Software Foundation version 2 of the License.
13
14 SYSFS=/sys
15 RESULT=1
16 TYPE=
17 OPWD="`pwd`"
18 full_sysfs_path=
19 full_sysfs_device_path=
20
21 if [ -z "$DEVPATH" -a -z "$1" ] ; then
22         exit 1
23 fi
24
25 if [ -z "$DEVPATH" ] ; then
26         case "$1" in
27                 $SYSFS/*)
28                         DEVPATH="${1#$SYSFS}"
29                         ;;
30                 *)
31                         DEVPATH=$1
32                         ;;
33         esac
34 fi
35
36 if [ ! -e $SYSFS$DEVPATH/dev ] ; then
37         exit 1
38 fi
39
40 case "$DEVPATH" in
41         /devices/*)
42                 cd "$SYSFS$DEVPATH/subsystem";
43                 TYPE="`pwd -P`"
44                 cd "$OPWD"
45                 TYPE="${TYPE##*/}"
46                 ;;
47         /class/*)
48                 TYPE="${DEVPATH#/class/}"
49                 TYPE="${TYPE%%/*}"
50                 ;;
51         /block/*)
52                 TYPE=block
53                 ;;
54         *)
55                 exit 1
56                 ;;
57 esac
58
59 get_port_offset () {
60         local type offset port
61         type=$1
62         offset=$2
63         for i in $type[0-9]* ; do
64                 : i $i
65                 port="${i#$type}"
66                 if [ "$port" -lt "$offset" ] ; then offset=$port ; fi
67         done
68         echo $offset
69 }
70
71 handle_pci () {
72         local DEV=$1
73         cd -P $1
74         DEV=${PWD}
75         pci_id=${DEV##*/}
76         host_dev_path=$DEV
77
78         # cciss devices don't have a separate sysfs node
79         for blk_link in block*; do
80             if [ -L "$blk_link" ]; then
81                 case "$blk_link" in
82                     *cciss*)
83                         d=cciss-${blk_link#*cciss\!}
84                         ;;
85                 esac
86             fi
87         done
88         while [ ! -z "$host_dev_path" ] ; do
89                 case "$host_dev_path" in
90                         */pci[0-9]*)
91                                 host_dev_path=${host_dev_path%/*}
92                                 ;;
93                         *)
94                                 break
95                                 ;;
96                 esac
97         done
98         if [ "$d" ]; then
99                 d="pci-$pci_id-$d"
100         else
101                 d="pci-$pci_id"
102         fi
103         D="$host_dev_path"
104         RESULT=0
105 }
106
107 handle_platform () {
108         local DEV=$1
109         cd -P $1
110         DEV=${PWD}
111         platform_id=${DEV##*/}
112         host_dev_path=$DEV
113         while [ ! -z "$host_dev_path" ] ; do
114                 case "$host_dev_path" in
115                         */platform*)
116                                 host_dev_path=${host_dev_path%/*}
117                                 ;;
118                         *)
119                                 break
120                                 ;;
121                 esac
122         done
123         if [ "$d" ]; then
124                 d="platform-$platform_id-$d"
125         else
126                 d="platform-$platform_id"
127         fi
128         D="$host_dev_path"
129         RESULT=0
130 }
131
132 handle_xen () {
133         local DEV=$1
134         cd -P $1
135         vbd_id=${DEV##*/}
136         host_dev_path=$DEV
137         while [ ! -z "$host_dev_path" ] ; do
138                 case "$host_dev_path" in
139                         */vbd*)
140                                 host_dev_path=${host_dev_path%/*}
141                                 ;;
142                         *)
143                                 break
144                                 ;;
145                 esac
146         done
147         if [ "$d" ]; then
148                 d="xen-$vbd_id-$d"
149         else
150                 d="xen-$vbd_id"
151         fi
152         D="$host_dev_path"
153         RESULT=0
154 }
155
156 handle_serio () {
157         local DEV=$1
158         cd -P $1
159         DEV=${PWD}
160         serio_id=${DEV##*/serio}
161         host_dev_path=$DEV
162         while [ ! -z "$host_dev_path" ] ; do
163                 case "$host_dev_path" in
164                         */serio*)
165                                 host_dev_path=${host_dev_path%/*}
166                                 ;;
167                         *)
168                                 break
169                                 ;;
170                 esac
171         done
172         if [ "$d" ]; then
173                 d="serio-$serio_id-$d"
174         else
175                 d="serio-$serio_id"
176         fi
177         D="$host_dev_path"
178         RESULT=0
179 }
180
181 handle_ide () {
182         : handle_ide $*
183         local DEV=$1
184         local port idedev idecontroller
185         # IDE
186         : DEV $DEV
187         port=${DEV##*/}
188         idedev=${DEV%/*}
189         idecontroller=${idedev%/*}
190         # port info if the controller has more than one interface
191         port="${port#ide}"
192         : port $port d $d
193         : idedev $idedev kernel_port $port
194         case "${port#*.}" in
195                 0)
196                         channel=0
197                         ;;
198                 1)
199                         channel=1
200                         ;;
201                 *)
202                         echo "Error: $idedev is neither master or slave" >&2
203                         ;;
204         esac
205         cd $idecontroller
206         offset="`get_port_offset ide ${port%.*}`"
207         cd "$OPWD"
208         :  port offset $offset
209         port=$((${port%.*} - $offset))
210         if [ "$d" ] ; then
211                 d="ide-${port}:$channel-$d"
212         else
213                 d="ide-${port}:$channel"
214         fi
215         D=$idecontroller
216         RESULT=0
217 }
218
219 handle_scsi () {
220         : handle_scsi $*
221         local DEV=$1
222         local cil controller_port controller_dev
223         # SCSI device
224         cil="${DEV##*/}"
225         cil="${cil#*:}"
226         target_dev=${DEV%/*}
227         target_id=${target_dev##*/target}
228         cd "$target_dev"
229         target_num=0
230         for tid in ${target_id}* ; do
231                 target_num=$(( $target_num + 1 ))
232         done
233         controller_port=${target_dev%/*}
234         controller_dev="${controller_port%/*}"
235         : controller_dev $controller_dev
236         : controller_port $controller_port
237         # a host controller may have more than one interface/port
238         controller_port="${controller_port##*/host}"
239         #
240         cd "$controller_dev"
241         controller_offset=$(get_port_offset host $controller_port)
242         cd "$OPWD"
243         controller_port=$(( $controller_port - $controller_offset))
244         scsi_id="scsi-${controller_port}:${cil}"
245         if [ "$d" ] ; then
246                 d="${scsi_id}-$d"
247         else
248                 d="$scsi_id"
249         fi
250         D="$controller_dev"
251         RESULT=0
252 }
253
254 handle_firewire () {
255         : handle_firewire $*
256         local DEV=$1
257         if [ -f "$D/ieee1394_id" ] ; then
258                 read ieee1394_id < $D/ieee1394_id
259         fi
260         if [ -z "$ieee1394_id" ] ; then
261                 : no IEEE1394 ID
262                 RESULT=1
263                 return
264         fi
265         fw_host_dev=${DEV%/fw-host*}
266         # IEEE1394 devices are always endpoints
267         d="ieee1394-0x$ieee1394_id"
268         D="$fw_host_dev"
269         RESULT=0
270 }
271
272 handle_fc () {
273         : handle_fc $*
274         local DEV=$1
275         local cil controller_port controller_dev
276         # SCSI-FC device
277         fc_tgt_hcil="${DEV##*/}"
278         fc_tgt_lun="${fc_tgt_hcil##*:}"
279         fc_tgt_path="${DEV%/*}"
280         fc_tgt_num="${fc_tgt_path##*/}"
281         fc_tgt_dev="${fc_tgt_path}/fc_transport/${fc_tgt_num}"
282         if [ -e "$fc_tgt_dev/port_name" ]; then
283                 read wwpn < $fc_tgt_dev/port_name
284         fi
285         if [ -z "$wwpn" ] ; then
286                 : no WWPN
287                 D=
288                 RESULT=1
289                 return
290         fi
291         # Linux currently knows about 32bit luns
292         tmp_lun3=$(printf "%04x" $(($fc_tgt_lun & 0xFFFF)))
293         tmp_lun2=$(printf "%04x" $(( ($fc_tgt_lun >> 16) & 0xFFFF)))
294         tmp_lun1="0000"
295         tmp_lun0="0000"
296         if (($fc_tgt_lun == 0)) ; then
297                 lun="0x0000000000000000"
298         else
299                 lun="0x${tmp_lun3}${tmp_lun2}${tmp_lun1}${tmp_lun0}"
300         fi
301         controller_dev="${fc_tgt_path%/host[0-9]*}"
302         # FC devices are always endpoints
303         d="fc-${wwpn}:${lun}"
304         D="$controller_dev"
305         RESULT=0
306 }
307
308 handle_sas () {
309         : handle_sas $*
310         local DEV=$1
311         local cil adapter controller_dev
312         local lun
313         lun=${DEV##*:}
314         # SAS device
315         sas_end_path="${DEV%%/target*}"
316         sas_host_path="${sas_end_path%%/port*}"
317         sas_phy_path="${sas_end_path#*/host*/}"
318         sas_phy_path="${sas_phy_path%%/*}"
319         sas_phy_path="${sas_host_path}/${sas_phy_path}"
320
321         sas_phy_id=255
322         for phy in $sas_phy_path/phy-*/sas_phy/phy-* ; do
323                 if [ -d "$phy" ] ; then
324                         read phy_id < $phy/phy_identifier
325                         if [ $phy_id -lt $sas_phy_id ]; then
326                                 sas_phy_id=$phy_id
327                         fi
328                 fi
329         done
330
331         if [ $sas_phy_id -eq 255 ] ; then
332                 : no initiator address
333                 D=
334                 RESULT=1
335                 return
336         fi
337
338         sas_port_id="${sas_phy_path##*/port-}"
339         sas_port_dev="/sys/class/sas_port/port-${sas_port_id}"
340         if [ -e "$sas_port_dev/num_phys" ] ; then
341                 read phy_port < $sas_port_dev/num_phys
342         fi
343
344         sas_end_id="${sas_end_path##*end_device-}"
345         sas_end_dev="/sys/class/sas_device/end_device-${sas_end_id}"
346         if [ -e "$sas_end_dev/sas_address" ]; then
347                 read end_address < $sas_end_dev/sas_address
348                 read end_id < $sas_end_dev/phy_identifier
349         fi
350         if [ -z "$end_address" ] ; then
351                 : no end device address
352                 D=
353                 RESULT=1
354                 return
355         fi
356         sas_end_address="$end_address:$end_id"
357         controller_dev="${sas_host_path%/host[0-9]*}"
358         # SAS devices are always endpoints
359         d="sas-phy${sas_phy_id}:${phy_port}-${sas_end_address}-lun$lun"
360         D="$controller_dev"
361         RESULT=0
362 }
363
364 handle_iscsi() {
365         local DEV=$1
366         local iscsi_session_dir
367         local iscsi_session iscsi_session_path
368         local iscsi_connection iscsi_connection_path
369         local iscsi_scsi_lun
370         # iSCSI device
371         iscsi_session_dir="${DEV%%/target*}"
372         iscsi_session="${iscsi_session_dir##*/}"
373         iscsi_session_path=/sys/class/iscsi_session/${iscsi_session}
374         if [ ! -d "$iscsi_session_path" ] ; then
375             : no iSCSI session path
376             RESULT=1
377             return
378         fi
379         # Currently we're not doing MC/S
380         for conn in ${iscsi_session_dir}/connection* ; do
381             iscsi_conn_num=${conn##*:}
382             if [ "$iscsi_conn_num" = '0' ] ; then
383                 iscsi_connection=$(basename $conn)
384             fi
385         done
386         if [ -z "$iscsi_connection" ] ; then
387             : no iSCSI connection found
388             RESULT=1
389             return
390         fi
391         iscsi_connection_path=/sys/class/iscsi_connection/${iscsi_connection}
392         if [ ! -d "$iscsi_connection_path" ] ; then
393             : no iSCSI connection path
394             RESULT=1
395             return
396         fi
397         if [ -e "${iscsi_session_path}/targetname" ]; then
398             read iscsi_tgtname < ${iscsi_session_path}/targetname
399         fi
400         if [ -z "$iscsi_tgtname" ] ; then
401             : No iSCSI Targetname
402             RESULT=1
403             return
404         fi
405         if [ -e "${iscsi_connection_path}/persistent_address" ] ; then
406             read iscsi_address < ${iscsi_connection_path}/persistent_address
407         fi
408         if [ -z "$iscsi_address" ] ; then
409             : No iSCSI Target address
410             RESULT=1
411             return
412         fi
413         if [ -e "${iscsi_connection_path}/persistent_port" ] ; then
414             read iscsi_port < ${iscsi_connection_path}/persistent_port
415         fi
416         iscsi_scsi_lun="${DEV##*:}"
417         d="ip-${iscsi_address}:${iscsi_port}-iscsi-${iscsi_tgtname}-lun-${iscsi_scsi_lun}"
418         RESULT=0
419 }
420
421 handle_usb () {
422 : handle_usb $*
423         local DEV=$1
424         cd -P $1
425         DEV=${PWD}
426         port_id=${DEV##*/}
427         port_num=${port_id#*-}
428         host_dev_path=$DEV
429         while [ ! -z "$host_dev_path" ] ; do
430                 case "$host_dev_path" in
431                         */usb*)
432                                 usb_host_path=$host_dev_path
433                                 host_dev_path="${host_dev_path%/*}"
434                                 ;;
435                         *)
436                                 break
437                                 ;;
438                 esac
439         done
440         : host_dev_path $host_dev_path
441         usb_host_num=${usb_host_path##*/usb}
442
443         cd "$host_dev_path"
444         usb_host_offset=$(get_port_offset usb $usb_host_num)
445         usb_host_port=$(($usb_host_num - $usb_host_offset))
446         cd "$OPWD"
447         if [ "$d" ] ; then
448                 d="usb-$usb_host_port:$port_num-${d}"
449         else
450                 d="usb-$usb_host_port:$port_num"
451         fi
452         D="$host_dev_path"
453         RESULT=0
454 }
455
456 handle_device () {
457         full_sysfs_path="$SYSFS$DEVPATH"
458         case "$DEVPATH" in
459                 /devices/*)
460                         full_sysfs_path="${full_sysfs_path%/*}"
461                         # skip parent device of the same subsystem
462                         if [ -L $full_sysfs_path/subsystem ]; then
463                                 cd "$full_sysfs_path/subsystem";
464                                 subsys="`pwd -P`"
465                                 cd "$OPWD"
466                                 subsys="${subsys##*/}"
467                                 if [ "$subsys" = "$TYPE" ]; then
468                                         : skip same subsystem parent
469                                         full_sysfs_path="${full_sysfs_path%/*}"
470                                 fi
471                         fi
472                         # skip subsystem directory
473                         subsys="${full_sysfs_path##*/}"
474                         if [ "$subsys" = "$TYPE" ]; then
475                                 : skip subsystem directory
476                                 full_sysfs_path="${full_sysfs_path%/*}"
477                         fi
478                         cd $full_sysfs_path
479                         ;;
480                 *)
481                         # old sysfs layout
482                         if [ ! -L $full_sysfs_path/device ]; then
483                                 full_sysfs_path="${full_sysfs_path%/*}"
484                                 : full_sysfs_path "$full_sysfs_path"
485                                 if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ]; then
486                                         return
487                                 fi
488                         fi
489                         if [ -L $full_sysfs_path/device/device ]; then
490                                 cd $full_sysfs_path/device/device
491                         else
492                                 cd $full_sysfs_path/device
493                         fi
494                         ;;
495         esac
496         full_sysfs_device_path="`pwd -P`"
497         cd "$OPWD"
498
499         D=$full_sysfs_device_path
500         while [ ! -z "$D" ] ; do
501                 case "$D" in
502                         */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
503                                 handle_ide "$D"
504                                 ;;
505                         */css0/*)
506                                 if [ -r $full_sysfs_device_path/wwpn ]; then
507                                         read wwpn < $full_sysfs_device_path/wwpn
508                                 fi
509                                 if [ -r $full_sysfs_device_path/fcp_lun ]; then
510                                         read lun < $full_sysfs_device_path/fcp_lun
511                                 fi
512                                 if [ -r $full_sysfs_device_path/hba_id ]; then
513                                         read bus_id < $full_sysfs_device_path/hba_id
514                                 fi
515                                 if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
516                                         # S/390 zfcp adapter
517                                         d="ccw-$bus_id-zfcp-$wwpn:$lun"
518                                         RESULT=0
519                                 else
520                                         # DASD devices
521                                         bus="ccw"
522                                         adapter=${D##*/}
523                                         d="$bus-$adapter"
524                                         RESULT=0
525                                 fi
526                                 D=
527                                 ;;
528                         */rport-[0-9]*:[0-9]*-[0-9]*/*)
529                                 handle_fc "$D"
530                                 ;;
531                         */end_device-[0-9]*:[0-9]*:[0-9]*/*)
532                                 handle_sas "$D"
533                                 ;;
534                         */fw-host[0-9]*/*)
535                                 handle_firewire "$D"
536                                 ;;
537                         */session[0-9]*/*)
538                                 handle_iscsi "$D"
539                                 D=
540                                 ;;
541                         */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
542                                 handle_scsi "$D"
543                                 ;;
544                         */ttyUSB*)
545                                 D=${D%/ttyUSB*}
546                                 ;;
547                         */usb[0-9]*/[0-9]*/*)
548                                 handle_usb "$D"
549                                 ;;
550                         */pci[0-9]*:[0-9]*)
551                                 handle_pci "$D"
552                                 ;;
553                         */serio[0-9]*)
554                                 handle_serio "$D"
555                                 ;;
556                         */platform/*)
557                                 handle_platform "$D"
558                                 ;;
559                         */vbd-[0-9]*)
560                                 handle_xen "$D"
561                                 ;;
562                         */devices)
563                                 D=
564                                 ;;
565                         *)
566                                 : not handled
567                                 RESULT=1
568                                 return
569                                 ;;
570                 esac
571         done
572         if [ "$TYPE" = "scsi_tape" ] ; then
573                 devname=${full_sysfs_path##*/}
574                 rewind="${devname%%st*}"
575                 mode="${devname##*st}"
576                 case "$mode" in
577                         *l)
578                                 mode="l"
579                                 ;;
580                         *m)
581                                 mode="m"
582                                 ;;
583                         *a)
584                                 mode="a"
585                                 ;;
586                         *)
587                                 mode=""
588                                 ;;
589                 esac
590                 if [ "$d" ]; then
591                         d="$d-${rewind}st${mode}"
592                 fi
593         fi
594 }
595
596 handle_device
597 if [ -z "$d" ]; then
598         exit 1
599 fi
600 echo "ID_PATH=$d"
601 exit 0