The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/udev/vdev_id

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #!/bin/sh
    2 #
    3 # vdev_id: udev helper to generate user-friendly names for JBOD disks
    4 #
    5 # This script parses the file /etc/zfs/vdev_id.conf to map a
    6 # physical path in a storage topology to a channel name.  The
    7 # channel name is combined with a disk enclosure slot number to
    8 # create an alias that reflects the physical location of the drive.
    9 # This is particularly helpful when it comes to tasks like replacing
   10 # failed drives.  Slot numbers may also be re-mapped in case the
   11 # default numbering is unsatisfactory.  The drive aliases will be
   12 # created as symbolic links in /dev/disk/by-vdev.
   13 #
   14 # The currently supported topologies are sas_direct and sas_switch.
   15 # A multipath mode is supported in which dm-mpath devices are
   16 # handled by examining the first-listed running component disk.  In
   17 # multipath mode the configuration file should contain a channel
   18 # definition with the same name for each path to a given enclosure.
   19 #
   20 # The alias keyword provides a simple way to map already-existing
   21 # device symlinks to more convenient names.  It is suitable for
   22 # small, static configurations or for sites that have some automated
   23 # way to generate the mapping file.
   24 #
   25 #
   26 # Some example configuration files are given below.
   27 
   28 # #
   29 # # Example vdev_id.conf - sas_direct.
   30 # #
   31 #
   32 # multipath     no
   33 # topology      sas_direct
   34 # phys_per_port 4
   35 # slot          bay
   36 #
   37 # #       PCI_ID  HBA PORT  CHANNEL NAME
   38 # channel 85:00.0 1         A
   39 # channel 85:00.0 0         B
   40 # channel 86:00.0 1         C
   41 # channel 86:00.0 0         D
   42 #
   43 # # Custom mapping for Channel A
   44 #
   45 # #    Linux      Mapped
   46 # #    Slot       Slot      Channel
   47 # slot 1          7         A
   48 # slot 2          10        A
   49 # slot 3          3         A
   50 # slot 4          6         A
   51 #
   52 # # Default mapping for B, C, and D
   53 # slot 1          4
   54 # slot 2          2
   55 # slot 3          1
   56 # slot 4          3
   57 
   58 # #
   59 # # Example vdev_id.conf - sas_switch
   60 # #
   61 #
   62 # topology      sas_switch
   63 #
   64 # #       SWITCH PORT  CHANNEL NAME
   65 # channel 1            A
   66 # channel 2            B
   67 # channel 3            C
   68 # channel 4            D
   69 
   70 # #
   71 # # Example vdev_id.conf - multipath
   72 # #
   73 #
   74 # multipath yes
   75 #
   76 # #       PCI_ID  HBA PORT  CHANNEL NAME
   77 # channel 85:00.0 1         A
   78 # channel 85:00.0 0         B
   79 # channel 86:00.0 1         A
   80 # channel 86:00.0 0         B
   81 
   82 # #
   83 # # Example vdev_id.conf - multipath / multijbod-daisychaining
   84 # #
   85 #
   86 # multipath yes
   87 # multijbod yes
   88 #
   89 # #       PCI_ID  HBA PORT  CHANNEL NAME
   90 # channel 85:00.0 1         A
   91 # channel 85:00.0 0         B
   92 # channel 86:00.0 1         A
   93 # channel 86:00.0 0         B
   94 
   95 # #
   96 # # Example vdev_id.conf - multipath / mixed
   97 # #
   98 #
   99 # multipath yes
  100 # slot mix
  101 #
  102 # #       PCI_ID  HBA PORT  CHANNEL NAME
  103 # channel 85:00.0 3         A
  104 # channel 85:00.0 2         B
  105 # channel 86:00.0 3         A
  106 # channel 86:00.0 2         B
  107 # channel af:00.0 0         C
  108 # channel af:00.0 1         C
  109 
  110 # #
  111 # # Example vdev_id.conf - alias
  112 # #
  113 #
  114 # #     by-vdev
  115 # #     name     fully qualified or base name of device link
  116 # alias d1       /dev/disk/by-id/wwn-0x5000c5002de3b9ca
  117 # alias d2       wwn-0x5000c5002def789e
  118 
  119 PATH=/bin:/sbin:/usr/bin:/usr/sbin
  120 CONFIG=/etc/zfs/vdev_id.conf
  121 PHYS_PER_PORT=
  122 DEV=
  123 TOPOLOGY=
  124 BAY=
  125 ENCL_ID=""
  126 UNIQ_ENCL_ID=""
  127 
  128 usage() {
  129         cat << EOF
  130 Usage: vdev_id [-h]
  131        vdev_id <-d device> [-c config_file] [-p phys_per_port]
  132                [-g sas_direct|sas_switch|scsi] [-m]
  133 
  134   -c    specify name of an alternative config file [default=$CONFIG]
  135   -d    specify basename of device (i.e. sda)
  136   -e    Create enclose device symlinks only (/dev/by-enclosure)
  137   -g    Storage network topology [default="$TOPOLOGY"]
  138   -m    Run in multipath mode
  139   -j    Run in multijbod mode
  140   -p    number of phy's per switch port [default=$PHYS_PER_PORT]
  141   -h    show this summary
  142 EOF
  143         exit 1
  144         # exit with error to avoid processing usage message by a udev rule
  145 }
  146 
  147 map_slot() {
  148         LINUX_SLOT=$1
  149         CHANNEL=$2
  150 
  151         MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \
  152                         '$1 == "slot" && $2 == linux_slot && \
  153                         ($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
  154         if [ -z "$MAPPED_SLOT" ] ; then
  155                 MAPPED_SLOT=$LINUX_SLOT
  156         fi
  157         printf "%d" "${MAPPED_SLOT}"
  158 }
  159 
  160 map_channel() {
  161         MAPPED_CHAN=
  162         PCI_ID=$1
  163         PORT=$2
  164 
  165         case $TOPOLOGY in
  166                 "sas_switch")
  167                 MAPPED_CHAN=$(awk -v port="$PORT" \
  168                         '$1 == "channel" && $2 == port \
  169                         { print $3; exit }' $CONFIG)
  170                 ;;
  171                 "sas_direct"|"scsi")
  172                 MAPPED_CHAN=$(awk -v pciID="$PCI_ID" -v port="$PORT" \
  173                         '$1 == "channel" && $2 == pciID && $3 == port \
  174                         {print $4}' $CONFIG)
  175                 ;;
  176         esac
  177         printf "%s" "${MAPPED_CHAN}"
  178 }
  179 
  180 get_encl_id() {
  181         set -- $(echo $1)
  182         count=$#
  183 
  184         i=1
  185         while [ $i -le $count ] ; do
  186                 d=$(eval echo '$'{$i})
  187                 id=$(cat "/sys/class/enclosure/${d}/id")
  188                 ENCL_ID="${ENCL_ID} $id"
  189                 i=$((i + 1))
  190         done
  191 }
  192 
  193 get_uniq_encl_id() {
  194         for uuid in ${ENCL_ID}; do
  195                 found=0
  196 
  197                 for count in ${UNIQ_ENCL_ID}; do
  198                         if [ $count = $uuid ]; then
  199                                 found=1
  200                                 break
  201                         fi
  202                 done
  203 
  204                 if [ $found -eq 0 ]; then
  205                         UNIQ_ENCL_ID="${UNIQ_ENCL_ID} $uuid"
  206                 fi
  207         done
  208 }
  209 
  210 # map_jbod explainer: The bsg driver knows the difference between a SAS
  211 # expander and fanout expander. Use hostX instance along with top-level
  212 # (whole enclosure) expander instances in /sys/class/enclosure and
  213 # matching a field in an array of expanders, using the index of the
  214 # matched array field as the enclosure instance, thereby making jbod IDs
  215 # dynamic. Avoids reliance on high overhead userspace commands like
  216 # multipath and lsscsi and instead uses existing sysfs data.  $HOSTCHAN
  217 # variable derived from devpath gymnastics in sas_handler() function.
  218 map_jbod() {
  219         DEVEXP=$(ls -l "/sys/block/$DEV/device/" | grep enclos | awk -F/ '{print $(NF-1) }')
  220         DEV=$1
  221 
  222         # Use "set --" to create index values (Arrays)
  223         set -- $(ls -l /sys/class/enclosure | grep -v "^total" | awk '{print $9}')
  224         # Get count of total elements
  225         JBOD_COUNT=$#
  226         JBOD_ITEM=$*
  227 
  228         # Build JBODs (enclosure)  id from sys/class/enclosure/<dev>/id
  229         get_encl_id "$JBOD_ITEM"
  230         # Different expander instances for each paths.
  231         # Filter out and keep only unique id.
  232         get_uniq_encl_id
  233 
  234         # Identify final 'mapped jbod'
  235         j=0
  236         for count in ${UNIQ_ENCL_ID}; do
  237                 i=1
  238                 j=$((j + 1))
  239                 while [ $i -le $JBOD_COUNT ] ; do
  240                         d=$(eval echo '$'{$i})
  241                         id=$(cat "/sys/class/enclosure/${d}/id")
  242                         if [ "$d" = "$DEVEXP" ] && [ $id = $count ] ; then
  243                                 MAPPED_JBOD=$j
  244                                 break
  245                         fi
  246                         i=$((i + 1))
  247                 done
  248         done
  249 
  250         printf "%d" "${MAPPED_JBOD}"
  251 }
  252 
  253 sas_handler() {
  254         if [ -z "$PHYS_PER_PORT" ] ; then
  255                 PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
  256                         {print $2; exit}' $CONFIG)
  257         fi
  258         PHYS_PER_PORT=${PHYS_PER_PORT:-4}
  259 
  260         if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
  261                 echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
  262                 exit 1
  263         fi
  264 
  265         if [ -z "$MULTIPATH_MODE" ] ; then
  266                 MULTIPATH_MODE=$(awk '$1 == "multipath" \
  267                         {print $2; exit}' $CONFIG)
  268         fi
  269 
  270         if [ -z "$MULTIJBOD_MODE" ] ; then
  271                 MULTIJBOD_MODE=$(awk '$1 == "multijbod" \
  272                         {print $2; exit}' $CONFIG)
  273         fi
  274 
  275         # Use first running component device if we're handling a dm-mpath device
  276         if [ "$MULTIPATH_MODE" = "yes" ] ; then
  277                 # If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
  278                 if [ -z "$DM_NAME" ] ; then
  279                         DM_NAME=$(ls -l --full-time /dev/mapper |
  280                                 grep "$DEV"$ | awk '{print $9}')
  281                 fi
  282 
  283                 # For raw disks udev exports DEVTYPE=partition when
  284                 # handling partitions, and the rules can be written to
  285                 # take advantage of this to append a -part suffix.  For
  286                 # dm devices we get DEVTYPE=disk even for partitions so
  287                 # we have to append the -part suffix directly in the
  288                 # helper.
  289                 if [ "$DEVTYPE" != "partition" ] ; then
  290                         # Match p[number], remove the 'p' and prepend "-part"
  291                         PART=$(echo "$DM_NAME" |
  292                                 awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
  293                 fi
  294 
  295                 # Strip off partition information.
  296                 DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
  297                 if [ -z "$DM_NAME" ] ; then
  298                         return
  299                 fi
  300 
  301                 # Utilize DM device name to gather subordinate block devices
  302                 # using sysfs to avoid userspace utilities
  303 
  304                 # If our DEVNAME is something like /dev/dm-177, then we may be
  305                 # able to get our DMDEV from it.
  306                 DMDEV=$(echo $DEVNAME | sed 's;/dev/;;g')
  307                 if [ ! -e /sys/block/$DMDEV/slaves/* ] ; then
  308                         # It's not there, try looking in /dev/mapper
  309                         DMDEV=$(ls -l --full-time /dev/mapper | grep $DM_NAME |
  310                         awk '{gsub("../", " "); print $NF}')
  311                 fi
  312 
  313                 # Use sysfs pointers in /sys/block/dm-X/slaves because using
  314                 # userspace tools creates lots of overhead and should be avoided
  315                 # whenever possible. Use awk to isolate lowest instance of
  316                 # sd device member in dm device group regardless of string
  317                 # length.
  318                 DEV=$(ls "/sys/block/$DMDEV/slaves" | awk '
  319                         { len=sprintf ("%20s",length($0)); gsub(/ /,0,str); a[NR]=len "_" $0; }
  320                         END {
  321                                 asort(a)
  322                                 print substr(a[1],22)
  323                         }')
  324 
  325                 if [ -z "$DEV" ] ; then
  326                         return
  327                 fi
  328         fi
  329 
  330         if echo "$DEV" | grep -q ^/devices/ ; then
  331                 sys_path=$DEV
  332         else
  333                 sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
  334         fi
  335 
  336         # Use positional parameters as an ad-hoc array
  337         set -- $(echo "$sys_path" | tr / ' ')
  338         num_dirs=$#
  339         scsi_host_dir="/sys"
  340 
  341         # Get path up to /sys/.../hostX
  342         i=1
  343 
  344         while [ $i -le "$num_dirs" ] ; do
  345                 d=$(eval echo '$'{$i})
  346                 scsi_host_dir="$scsi_host_dir/$d"
  347                 echo "$d" | grep -q -E '^host[0-9]+$' && break
  348                 i=$((i + 1))
  349         done
  350 
  351         # Lets grab the SAS host channel number and save it for JBOD sorting later
  352         HOSTCHAN=$(echo "$d" | awk -F/ '{ gsub("host","",$NF); print $NF}')
  353 
  354         if [ $i = "$num_dirs" ] ; then
  355                 return
  356         fi
  357 
  358         PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
  359 
  360         # In sas_switch mode, the directory four levels beneath
  361         # /sys/.../hostX contains symlinks to phy devices that reveal
  362         # the switch port number.  In sas_direct mode, the phy links one
  363         # directory down reveal the HBA port.
  364         port_dir=$scsi_host_dir
  365 
  366         case $TOPOLOGY in
  367                 "sas_switch") j=$((i + 4)) ;;
  368                 "sas_direct") j=$((i + 1)) ;;
  369         esac
  370 
  371         i=$((i + 1))
  372 
  373         while [ $i -le $j ] ; do
  374                 port_dir="$port_dir/$(eval echo '$'{$i})"
  375                 i=$((i + 1))
  376         done
  377 
  378         PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
  379         if [ -z "$PHY" ] ; then
  380                 PHY=0
  381         fi
  382         PORT=$((PHY / PHYS_PER_PORT))
  383 
  384         # Look in /sys/.../sas_device/end_device-X for the bay_identifier
  385         # attribute.
  386         end_device_dir=$port_dir
  387 
  388         while [ $i -lt "$num_dirs" ] ; do
  389                 d=$(eval echo '$'{$i})
  390                 end_device_dir="$end_device_dir/$d"
  391                 if echo "$d" | grep -q '^end_device' ; then
  392                         end_device_dir="$end_device_dir/sas_device/$d"
  393                         break
  394                 fi
  395                 i=$((i + 1))
  396         done
  397 
  398         # Add 'mix' slot type for environments where dm-multipath devices
  399         # include end-devices connected via SAS expanders or direct connection
  400         # to SAS HBA. A mixed connectivity environment such as pool devices
  401         # contained in a SAS JBOD and spare drives or log devices directly
  402         # connected in a server backplane without expanders in the I/O path.
  403         SLOT=
  404 
  405         case $BAY in
  406         "bay")
  407                 SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
  408                 ;;
  409         "mix")
  410                 if [ $(cat "$end_device_dir/bay_identifier" 2>/dev/null) ] ; then
  411                         SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
  412                 else
  413                         SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
  414                 fi
  415                 ;;
  416         "phy")
  417                 SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
  418                 ;;
  419         "port")
  420                 d=$(eval echo '$'{$i})
  421                 SLOT=$(echo "$d" | sed -e 's/^.*://')
  422                 ;;
  423         "id")
  424                 i=$((i + 1))
  425                 d=$(eval echo '$'{$i})
  426                 SLOT=$(echo "$d" | sed -e 's/^.*://')
  427                 ;;
  428         "lun")
  429                 i=$((i + 2))
  430                 d=$(eval echo '$'{$i})
  431                 SLOT=$(echo "$d" | sed -e 's/^.*://')
  432                 ;;
  433         "ses")
  434                 # look for this SAS path in all SCSI Enclosure Services
  435                 # (SES) enclosures
  436                 sas_address=$(cat "$end_device_dir/sas_address" 2>/dev/null)
  437                 enclosures=$(lsscsi -g | \
  438                         sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p')
  439                 for enclosure in $enclosures; do
  440                         set -- $(sg_ses -p aes "$enclosure" | \
  441                                 awk "/device slot number:/{slot=\$12} \
  442                                         /SAS address: $sas_address/\
  443                                         {print slot}")
  444                         SLOT=$1
  445                         if [ -n "$SLOT" ] ; then
  446                                 break
  447                         fi
  448                 done
  449                 ;;
  450         esac
  451         if [ -z "$SLOT" ] ; then
  452                 return
  453         fi
  454 
  455         if [ "$MULTIJBOD_MODE" = "yes" ] ; then
  456                 CHAN=$(map_channel "$PCI_ID" "$PORT")
  457                 SLOT=$(map_slot "$SLOT" "$CHAN")
  458                 JBOD=$(map_jbod "$DEV")
  459 
  460                 if [ -z "$CHAN" ] ; then
  461                         return
  462                 fi
  463                 echo "${CHAN}"-"${JBOD}"-"${SLOT}${PART}"
  464         else
  465                 CHAN=$(map_channel "$PCI_ID" "$PORT")
  466                 SLOT=$(map_slot "$SLOT" "$CHAN")
  467 
  468                 if [ -z "$CHAN" ] ; then
  469                         return
  470                 fi
  471                 echo "${CHAN}${SLOT}${PART}"
  472         fi
  473 }
  474 
  475 scsi_handler() {
  476         if [ -z "$FIRST_BAY_NUMBER" ] ; then
  477                 FIRST_BAY_NUMBER=$(awk '$1 == "first_bay_number" \
  478                         {print $2; exit}' $CONFIG)
  479         fi
  480         FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
  481 
  482         if [ -z "$PHYS_PER_PORT" ] ; then
  483                 PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
  484                         {print $2; exit}' $CONFIG)
  485         fi
  486         PHYS_PER_PORT=${PHYS_PER_PORT:-4}
  487 
  488         if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
  489                 echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
  490                 exit 1
  491         fi
  492 
  493         if [ -z "$MULTIPATH_MODE" ] ; then
  494                 MULTIPATH_MODE=$(awk '$1 == "multipath" \
  495                         {print $2; exit}' $CONFIG)
  496         fi
  497 
  498         # Use first running component device if we're handling a dm-mpath device
  499         if [ "$MULTIPATH_MODE" = "yes" ] ; then
  500                 # If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
  501                 if [ -z "$DM_NAME" ] ; then
  502                         DM_NAME=$(ls -l --full-time /dev/mapper |
  503                                 grep "$DEV"$ | awk '{print $9}')
  504                 fi
  505 
  506                 # For raw disks udev exports DEVTYPE=partition when
  507                 # handling partitions, and the rules can be written to
  508                 # take advantage of this to append a -part suffix.  For
  509                 # dm devices we get DEVTYPE=disk even for partitions so
  510                 # we have to append the -part suffix directly in the
  511                 # helper.
  512                 if [ "$DEVTYPE" != "partition" ] ; then
  513                         # Match p[number], remove the 'p' and prepend "-part"
  514                         PART=$(echo "$DM_NAME" |
  515                             awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
  516                 fi
  517 
  518                 # Strip off partition information.
  519                 DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
  520                 if [ -z "$DM_NAME" ] ; then
  521                         return
  522                 fi
  523 
  524                 # Get the raw scsi device name from multipath -ll. Strip off
  525                 # leading pipe symbols to make field numbering consistent.
  526                 DEV=$(multipath -ll "$DM_NAME" |
  527                         awk '/running/{gsub("^[|]"," "); print $3 ; exit}')
  528                 if [ -z "$DEV" ] ; then
  529                         return
  530                 fi
  531         fi
  532 
  533         if echo "$DEV" | grep -q ^/devices/ ; then
  534                 sys_path=$DEV
  535         else
  536                 sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
  537         fi
  538 
  539         # expect sys_path like this, for example:
  540         # /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
  541 
  542         # Use positional parameters as an ad-hoc array
  543         set -- $(echo "$sys_path" | tr / ' ')
  544         num_dirs=$#
  545         scsi_host_dir="/sys"
  546 
  547         # Get path up to /sys/.../hostX
  548         i=1
  549 
  550         while [ $i -le "$num_dirs" ] ; do
  551                 d=$(eval echo '$'{$i})
  552                 scsi_host_dir="$scsi_host_dir/$d"
  553 
  554                 echo "$d" | grep -q -E '^host[0-9]+$' && break
  555                 i=$((i + 1))
  556         done
  557 
  558         if [ $i = "$num_dirs" ] ; then
  559                 return
  560         fi
  561 
  562         PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
  563 
  564         # In scsi mode, the directory two levels beneath
  565         # /sys/.../hostX reveals the port and slot.
  566         port_dir=$scsi_host_dir
  567         j=$((i + 2))
  568 
  569         i=$((i + 1))
  570         while [ $i -le $j ] ; do
  571                 port_dir="$port_dir/$(eval echo '$'{$i})"
  572                 i=$((i + 1))
  573         done
  574 
  575         set -- $(echo "$port_dir" | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
  576         PORT=$1
  577         SLOT=$(($2 + FIRST_BAY_NUMBER))
  578 
  579         if [ -z "$SLOT" ] ; then
  580                 return
  581         fi
  582 
  583         CHAN=$(map_channel "$PCI_ID" "$PORT")
  584         SLOT=$(map_slot "$SLOT" "$CHAN")
  585 
  586         if [ -z "$CHAN" ] ; then
  587                 return
  588         fi
  589         echo "${CHAN}${SLOT}${PART}"
  590 }
  591 
  592 # Figure out the name for the enclosure symlink
  593 enclosure_handler () {
  594         # We get all the info we need from udev's DEVPATH variable:
  595         #
  596         # DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
  597 
  598         # Get the enclosure ID ("0:0:0:0")
  599         ENC="${DEVPATH%/*}"
  600         ENC="${ENC%/*}"
  601         ENC="${ENC##*/}"
  602         if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
  603                 # Not an enclosure, bail out
  604                 return
  605         fi
  606 
  607         # Get the long sysfs device path to our enclosure. Looks like:
  608         # /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
  609 
  610         ENC_DEVICE=$(readlink "/sys/class/enclosure/$ENC")
  611 
  612         # Grab the full path to the hosts port dir:
  613         # /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
  614         PORT_DIR=$(echo "$ENC_DEVICE" | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
  615 
  616         # Get the port number
  617         PORT_ID=$(echo "$PORT_DIR" | grep -Eo "[0-9]+$")
  618 
  619         # The PCI directory is two directories up from the port directory
  620         # /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
  621         PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
  622         PCI_ID_LONG="${PCI_ID_LONG##*/}"
  623 
  624         # Strip down the PCI address from 0000:05:00.0 to 05:00.0
  625         PCI_ID="${PCI_ID_LONG#[0-9]*:}"
  626 
  627         # Name our device according to vdev_id.conf (like "L0" or "U1").
  628         NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
  629                 \$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
  630 
  631         echo "${NAME}"
  632 }
  633 
  634 alias_handler () {
  635         # Special handling is needed to correctly append a -part suffix
  636         # to partitions of device mapper devices.  The DEVTYPE attribute
  637         # is normally set to "disk" instead of "partition" in this case,
  638         # so the udev rules won't handle that for us as they do for
  639         # "plain" block devices.
  640         #
  641         # For example, we may have the following links for a device and its
  642         # partitions,
  643         #
  644         #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0   -> ../../dm-0
  645         #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p1 -> ../../dm-1
  646         #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p2 -> ../../dm-3
  647         #
  648         # and the following alias in vdev_id.conf.
  649         #
  650         #   alias A0 dm-name-isw_dibgbfcije_ARRAY0
  651         #
  652         # The desired outcome is for the following links to be created
  653         # without having explicitly defined aliases for the partitions.
  654         #
  655         #  /dev/disk/by-vdev/A0       -> ../../dm-0
  656         #  /dev/disk/by-vdev/A0-part1 -> ../../dm-1
  657         #  /dev/disk/by-vdev/A0-part2 -> ../../dm-3
  658         #
  659         # Warning: The following grep pattern will misidentify whole-disk
  660         #          devices whose names end with 'p' followed by a string of
  661         #          digits as partitions, causing alias creation to fail. This
  662         #          ambiguity seems unavoidable, so devices using this facility
  663         #          must not use such names.
  664         DM_PART=
  665         if echo "$DM_NAME" | grep -q -E 'p[0-9][0-9]*$' ; then
  666                 if [ "$DEVTYPE" != "partition" ] ; then
  667                         # Match p[number], remove the 'p' and prepend "-part"
  668                         DM_PART=$(echo "$DM_NAME" |
  669                             awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
  670                 fi
  671         fi
  672 
  673         # DEVLINKS attribute must have been populated by already-run udev rules.
  674         for link in $DEVLINKS ; do
  675                 # Remove partition information to match key of top-level device.
  676                 if [ -n "$DM_PART" ] ; then
  677                         link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
  678                 fi
  679                 # Check both the fully qualified and the base name of link.
  680                 for l in $link ${link##*/} ; do
  681                         if [ ! -z "$l" ]; then
  682                                 alias=$(awk -v var="$l" '($1 == "alias") && \
  683                                         ($3 == var) \
  684                                         { print $2; exit }' $CONFIG)
  685                                 if [ -n "$alias" ] ; then
  686                                         echo "${alias}${DM_PART}"
  687                                         return
  688                                 fi
  689                         fi
  690                 done
  691         done
  692 }
  693 
  694 # main
  695 while getopts 'c:d:eg:jmp:h' OPTION; do
  696         case ${OPTION} in
  697         c)
  698                 CONFIG=${OPTARG}
  699                 ;;
  700         d)
  701                 DEV=${OPTARG}
  702                 ;;
  703         e)
  704         # When udev sees a scsi_generic device, it calls this script with -e to
  705         # create the enclosure device symlinks only.  We also need
  706         # "enclosure_symlinks yes" set in vdev_id.config to actually create the
  707         # symlink.
  708         ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") \
  709                 print $2}' "$CONFIG")
  710 
  711         if [ "$ENCLOSURE_MODE" != "yes" ] ; then
  712                 exit 0
  713         fi
  714                 ;;
  715         g)
  716                 TOPOLOGY=$OPTARG
  717                 ;;
  718         p)
  719                 PHYS_PER_PORT=${OPTARG}
  720                 ;;
  721         j)
  722                 MULTIJBOD_MODE=yes
  723                 ;;
  724         m)
  725                 MULTIPATH_MODE=yes
  726                 ;;
  727         h)
  728                 usage
  729                 ;;
  730         esac
  731 done
  732 
  733 if [ ! -r "$CONFIG" ] ; then
  734         echo "Error: Config file \"$CONFIG\" not found"
  735         exit 1
  736 fi
  737 
  738 if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
  739         echo "Error: missing required option -d"
  740         exit 1
  741 fi
  742 
  743 if [ -z "$TOPOLOGY" ] ; then
  744         TOPOLOGY=$(awk '($1 == "topology") {print $2; exit}' "$CONFIG")
  745 fi
  746 
  747 if [ -z "$BAY" ] ; then
  748         BAY=$(awk '($1 == "slot") {print $2; exit}' "$CONFIG")
  749 fi
  750 
  751 TOPOLOGY=${TOPOLOGY:-sas_direct}
  752 
  753 # Should we create /dev/by-enclosure symlinks?
  754 if [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
  755         ID_ENCLOSURE=$(enclosure_handler)
  756         if [ -z "$ID_ENCLOSURE" ] ; then
  757                 exit 0
  758         fi
  759 
  760         # Just create the symlinks to the enclosure devices and then exit.
  761         ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' "$CONFIG")
  762         if [ -z "$ENCLOSURE_PREFIX" ] ; then
  763                 ENCLOSURE_PREFIX="enc"
  764         fi
  765         echo "ID_ENCLOSURE=$ID_ENCLOSURE"
  766         echo "ID_ENCLOSURE_PATH=by-enclosure/$ENCLOSURE_PREFIX-$ID_ENCLOSURE"
  767         exit 0
  768 fi
  769 
  770 # First check if an alias was defined for this device.
  771 ID_VDEV=$(alias_handler)
  772 
  773 if [ -z "$ID_VDEV" ] ; then
  774         BAY=${BAY:-bay}
  775         case $TOPOLOGY in
  776                 sas_direct|sas_switch)
  777                         ID_VDEV=$(sas_handler)
  778                         ;;
  779                 scsi)
  780                         ID_VDEV=$(scsi_handler)
  781                         ;;
  782                 *)
  783                         echo "Error: unknown topology $TOPOLOGY"
  784                         exit 1
  785                         ;;
  786         esac
  787 fi
  788 
  789 if [ -n "$ID_VDEV" ] ; then
  790         echo "ID_VDEV=${ID_VDEV}"
  791         echo "ID_VDEV_PATH=disk/by-vdev/${ID_VDEV}"
  792 fi

Cache object: 61e3825088927e038e8e52cb586b3b51


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.