5

I'm writing a script, and I'm interested in being able to identify the transport class (fc - "fibre channel", scsi, iscsi, etc.) for a given block device. I can retrieve this information via ls -l /dev/disk/by-path on RHEL, but I'd rather query sysfs if that's at all possible (for a variety of reasons, including portability). For example:

[root@localhost sde]# ls -l /dev/disk/by-path
total 0
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:0:0 -> ../../sda
lrwxrwxrwx 1 root root 10 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:0:0-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:0:0-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:0:0-part3 -> ../../sda3
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:1:0 -> ../../sdb
lrwxrwxrwx 1 root root 10 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:1:0-part1 -> ../../sdb1
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:2:0 -> ../../sdc
lrwxrwxrwx 1 root root 10 Jul 21 16:39 pci-0000:01:00.0-scsi-0:2:2:0-part1 -> ../../sdc1
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.0-fc-0x500601663ee0025f:0x0000000000000000 -> ../../sdd
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.0-fc-0x500601663ee0025f:0x0015000000000000 -> ../../sde
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.0-fc-0x5006016e3ee0025f:0x0000000000000000 -> ../../sdf
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.0-fc-0x5006016e3ee0025f:0x0015000000000000 -> ../../sdg
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.1-fc-0x500601653ee0025f:0x0000000000000000 -> ../../sdj
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.1-fc-0x500601653ee0025f:0x0015000000000000 -> ../../sdk
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.1-fc-0x5006016d3ee0025f:0x0000000000000000 -> ../../sdh
lrwxrwxrwx 1 root root  9 Jul 21 16:39 pci-0000:1a:00.1-fc-0x5006016d3ee0025f:0x0015000000000000 -> ../../sdi

But looking in /sys/block/sde I don't see anything particularly useful:

[root@localhost sde]# ls -l /sys/block/sde
total 0
-r--r--r-- 1 root root 4096 Oct 14 16:51 dev
lrwxrwxrwx 1 root root    0 Oct 14 16:51 device -> ../../devices/pci0000:00/0000:00:07.0/0000:1a:00.0/host5/rport-5:0-2/target5:0:0/5:0:0:21
drwxr-xr-x 2 root root    0 Jul 21 12:39 holders
drwxr-xr-x 3 root root    0 Jul 21 12:39 queue
-r--r--r-- 1 root root 4096 Oct 14 16:51 range
-r--r--r-- 1 root root 4096 Oct 14 16:51 removable
-r--r--r-- 1 root root 4096 Oct 14 16:51 size
drwxr-xr-x 2 root root    0 Jul 21 12:39 slaves
-r--r--r-- 1 root root 4096 Oct 14 16:51 stat
lrwxrwxrwx 1 root root    0 Oct 14 16:51 subsystem -> ../../block
--w------- 1 root root 4096 Oct 14 16:51 uevent

Any help is appreciated, even if it just pushes me in the right direction. My ideal solution is to use only sysfs data.

  • Hey Joel, what do you mean by transport protocol? – slm Oct 15 '13 at 0:26
  • Sorry I guess I was ambiguous there. For example, in the ls output above fc stands for "fibre channel" but there's also scsi and iscsi etc (not such but I think infiniband has a designation). Basically, it's the designation that shows you by what means the volume is being presented to the system, I'm looking for a way to differentiate local, fibre channel, mutlipath, and iSCSI devices. – Bratchley Oct 15 '13 at 0:59
3

Unless I get a better answer, I'm going to take this as my solution. It's very indirect but appears to work. Basically, I judged from the fact that udevd was able to make the path in /dev/disk/by-path, it must be in sysfs because to my knowledge that's all udev really does: Takes sysfs information and performs configured actions utilizing it.

After rummaging around it looks like those links get created by the contents of the ID_PATH variable which is set by way of the /lib/udev/id_path bash script. Inside that I found a case statement that basically lays out how it determines transport by checking for the existence of various directories directly underneath the sysfs entry for the given block device's source controller:

                    */rport-[0-9]*:[0-9]*-[0-9]*/*)
                            handle_fc "$D"
                            ;;
                    */end_device-[0-9]*:[0-9]*:[0-9]*/*)
                            handle_sas "$D"
                            ;;
                    */fw-host[0-9]*/*)
                            handle_firewire "$D"
                            ;;
                    */session[0-9]*/*)
                            handle_iscsi "$D"
                            D=
                            ;;
                    */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
                            handle_scsi "$D"
                            ;;
                    */usb[0-9]*/[0-9]*/*)
                            handle_usb "$D"
                            ;;
                    */pci[0-9]*:[0-9]*)
                            handle_pci "$D"
                            ;;
                    */serio[0-9]*)
                            handle_serio "$D"
                            ;;
                    */platform/*)
                            handle_platform "$D"
                            ;;
                    */devices)
                            D=
                            ;;

I tested this out on the command line by replicating the Fibre Channel test and got positive results:

## INTERNAL DRIVE:
[root@localhost sde]# ls -ld /sys/block/sda/device/../../../rport* 2>/dev/null | wc -l
0

## FIBRE CHANNEL BLOCK DEVICE:
[root@localhost sde]# ls -ld /sys/block/sde/device/../../../rport* 2>/dev/null | wc -l
4

Basically, I take the short name of the device (sda, sdb, sde, etc), enter the physical device, then .. until I'm up at the block device's source controller. If the controller's sysfs entry has rport* directories as immediate children, then that means the block device is coming in via fibre channel.

This only replicates the check for the first switch case (*/rport-[0-9]*:[0-9]*-[0-9]*/*)) for iscsi, I was also able to replicate the success by looking for "session[0-9]" directories on the controller:

[root@files2 ~]# ls -ld /sys/block/sda/device/../../../session[0-9]
drwxr-xr-x. 6 root root 0 Oct 15 13:50 /sys/block/sda/device/../../../session1
[root@files2 ~]#

My script is going to be written in Python but it looks like checking for these directories is sufficient. I'm going to go ahead and mark this as my solution (once it lets me anyways).

1

No systems to test this on other than my Fedora 19 system, but this may be a start:

$ ls -l /sys/block/sda/subsystem/sda
lrwxrwxrwx. 1 root root 0 Oct 14 21:41 /sys/block/sda/subsystem/sda -> ../../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda/

It's also interesting to note that my system has no /dev/disk/by-path.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.