From 2b8c3cb0c83681d7425fa5bf567e726b7ba975e9 Mon Sep 17 00:00:00 2001 From: Simon Guest Date: Thu, 28 Sep 2017 06:39:47 +1300 Subject: [PATCH] vdev_id: extension for new scsi topology On systems with SCSI rather than SAS disk topology, this change enables the vdev_id script to match against the block device path, and therefore create a vdev alias in /dev/disk/by-vdev. Reviewed-by: Tony Hutter Reviewed-by: Brian Behlendorf Signed-off-by: Simon Guest Closes #6592 --- cmd/vdev_id/vdev_id | 118 +++++++++++++++++++++++++++++- etc/zfs/Makefile.am | 3 +- etc/zfs/vdev_id.conf.scsi.example | 9 +++ 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 etc/zfs/vdev_id.conf.scsi.example diff --git a/cmd/vdev_id/vdev_id b/cmd/vdev_id/vdev_id index a2cba086e..9fa2d672c 100755 --- a/cmd/vdev_id/vdev_id +++ b/cmd/vdev_id/vdev_id @@ -100,7 +100,7 @@ usage() { cat << EOF Usage: vdev_id [-h] vdev_id <-d device> [-c config_file] [-p phys_per_port] - [-g sas_direct|sas_switch] [-m] + [-g sas_direct|sas_switch|scsi] [-m] -c specify name of alernate config file [default=$CONFIG] -d specify basename of device (i.e. sda) @@ -135,7 +135,7 @@ map_channel() { MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \ { print \\$3; exit }" $CONFIG` ;; - "sas_direct") + "sas_direct"|"scsi") MAPPED_CHAN=`awk "\\$1 == \"channel\" && \ \\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \ { print \\$4; exit }" $CONFIG` @@ -289,6 +289,117 @@ sas_handler() { echo ${CHAN}${SLOT}${PART} } +scsi_handler() { + if [ -z "$FIRST_BAY_NUMBER" ] ; then + FIRST_BAY_NUMBER=`awk "\\$1 == \"first_bay_number\" \ + {print \\$2; exit}" $CONFIG` + fi + FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0} + + if [ -z "$PHYS_PER_PORT" ] ; then + PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \ + {print \\$2; exit}" $CONFIG` + fi + PHYS_PER_PORT=${PHYS_PER_PORT:-4} + if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then + echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric" + exit 1 + fi + + if [ -z "$MULTIPATH_MODE" ] ; then + MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \ + {print \\$2; exit}" $CONFIG` + fi + + # Use first running component device if we're handling a dm-mpath device + if [ "$MULTIPATH_MODE" = "yes" ] ; then + # If udev didn't tell us the UUID via DM_NAME, check /dev/mapper + if [ -z "$DM_NAME" ] ; then + DM_NAME=`ls -l --full-time /dev/mapper | + awk "/\/$DEV$/{print \\$9}"` + fi + + # For raw disks udev exports DEVTYPE=partition when + # handling partitions, and the rules can be written to + # take advantage of this to append a -part suffix. For + # dm devices we get DEVTYPE=disk even for partitions so + # we have to append the -part suffix directly in the + # helper. + if [ "$DEVTYPE" != "partition" ] ; then + PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'` + fi + + # Strip off partition information. + DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'` + if [ -z "$DM_NAME" ] ; then + return + fi + + # Get the raw scsi device name from multipath -ll. Strip off + # leading pipe symbols to make field numbering consistent. + DEV=`multipath -ll $DM_NAME | + awk '/running/{gsub("^[|]"," "); print $3 ; exit}'` + if [ -z "$DEV" ] ; then + return + fi + fi + + if echo $DEV | grep -q ^/devices/ ; then + sys_path=$DEV + else + sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null` + fi + + # expect sys_path like this, for example: + # /devices/pci0000:00/0000:00:0b.0/0000:09:00.0/0000:0a:05.0/0000:0c:00.0/host3/target3:1:0/3:1:0:21/block/sdv + + # Use positional parameters as an ad-hoc array + set -- $(echo "$sys_path" | tr / ' ') + num_dirs=$# + scsi_host_dir="/sys" + + # Get path up to /sys/.../hostX + i=1 + while [ $i -le $num_dirs ] ; do + d=$(eval echo \${$i}) + scsi_host_dir="$scsi_host_dir/$d" + echo $d | grep -q -E '^host[0-9]+$' && break + i=$(($i + 1)) + done + + if [ $i = $num_dirs ] ; then + return + fi + + PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}') + + # In scsi mode, the directory two levels beneath + # /sys/.../hostX reveals the port and slot. + port_dir=$scsi_host_dir + j=$(($i + 2)) + + i=$(($i + 1)) + while [ $i -le $j ] ; do + port_dir="$port_dir/$(eval echo \${$i})" + i=$(($i + 1)) + done + + set -- $(echo $port_dir | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/') + PORT=$1 + SLOT=$(($2 + $FIRST_BAY_NUMBER)) + + if [ -z "$SLOT" ] ; then + return + fi + + CHAN=`map_channel $PCI_ID $PORT` + SLOT=`map_slot $SLOT $CHAN` + if [ -z "$CHAN" ] ; then + return + fi + echo ${CHAN}${SLOT}${PART} +} + alias_handler () { # Special handling is needed to correctly append a -part suffix # to partitions of device mapper devices. The DEVTYPE attribute @@ -394,6 +505,9 @@ if [ -z "$ID_VDEV" ] ; then sas_direct|sas_switch) ID_VDEV=`sas_handler` ;; + scsi) + ID_VDEV=`scsi_handler` + ;; *) echo "Error: unknown topology $TOPOLOGY" exit 1 diff --git a/etc/zfs/Makefile.am b/etc/zfs/Makefile.am index ff35469fe..52f6634df 100644 --- a/etc/zfs/Makefile.am +++ b/etc/zfs/Makefile.am @@ -4,6 +4,7 @@ pkgsysconf_DATA = \ vdev_id.conf.alias.example \ vdev_id.conf.sas_direct.example \ vdev_id.conf.sas_switch.example \ - vdev_id.conf.multipath.example + vdev_id.conf.multipath.example \ + vdev_id.conf.scsi.example EXTRA_DIST = $(pkgsysconf_DATA) diff --git a/etc/zfs/vdev_id.conf.scsi.example b/etc/zfs/vdev_id.conf.scsi.example new file mode 100644 index 000000000..b8c0ab2bf --- /dev/null +++ b/etc/zfs/vdev_id.conf.scsi.example @@ -0,0 +1,9 @@ +multipath no +topology scsi +phys_per_port 1 +# Usually scsi disks are numbered from 0, but this can be offset, to +# match the physical bay numbers, as follows: +first_bay_number 1 + +# PCI_ID HBA PORT CHANNEL NAME +channel 0c:00.0 0 Y -- 2.39.5