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/cmd/zed/zed.d/vdev_clear-led.sh

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 # shellcheck disable=SC2154
    3 #
    4 # Turn off/on vdevs' enclosure fault LEDs when their pool's state changes.
    5 #
    6 # Turn a vdev's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
    7 # Turn its LED off when it's back ONLINE again.
    8 #
    9 # This script run in two basic modes:
   10 #
   11 # 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
   12 # only set the LED for that particular vdev. This is the case for statechange
   13 # events and some vdev_* events.
   14 #
   15 # 2. If those vars are not set, then check the state of all vdevs in the pool
   16 # and set the LEDs accordingly.  This is the case for pool_import events.
   17 #
   18 # Note that this script requires that your enclosure be supported by the
   19 # Linux SCSI Enclosure services (SES) driver.  The script will do nothing
   20 # if you have no enclosure, or if your enclosure isn't supported.
   21 #
   22 # Exit codes:
   23 #   0: enclosure led successfully set
   24 #   1: enclosure leds not available
   25 #   2: enclosure leds administratively disabled
   26 #   3: The led sysfs path passed from ZFS does not exist
   27 #   4: $ZPOOL not set
   28 #   5: awk is not installed
   29 
   30 [ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
   31 . "${ZED_ZEDLET_DIR}/zed-functions.sh"
   32 
   33 if [ ! -d /sys/class/enclosure ] && [ ! -d /sys/bus/pci/slots ] ; then
   34         # No JBOD enclosure or NVMe slots
   35         exit 1
   36 fi
   37 
   38 if [ "${ZED_USE_ENCLOSURE_LEDS}" != "1" ] ; then
   39         exit 2
   40 fi
   41 
   42 zed_check_cmd "$ZPOOL" || exit 4
   43 zed_check_cmd awk || exit 5
   44 
   45 # Global used in set_led debug print
   46 vdev=""
   47 
   48 # check_and_set_led (file, val)
   49 #
   50 # Read an enclosure sysfs file, and write it if it's not already set to 'val'
   51 #
   52 # Arguments
   53 #   file: sysfs file to set (like /sys/class/enclosure/0:0:1:0/SLOT 10/fault)
   54 #   val: value to set it to
   55 #
   56 # Return
   57 #  0 on success, 3 on missing sysfs path
   58 #
   59 check_and_set_led()
   60 {
   61         file="$1"
   62         val="$2"
   63 
   64         if [ -z "$val" ]; then
   65                 return 0
   66         fi
   67 
   68         if [ ! -e "$file" ] ; then
   69                 return 3
   70         fi
   71 
   72         # If another process is accessing the LED when we attempt to update it,
   73         # the update will be lost so retry until the LED actually changes or we
   74         # timeout.
   75         for _ in 1 2 3 4 5; do
   76                 # We want to check the current state first, since writing to the
   77                 # 'fault' entry always causes a SES command, even if the
   78                 # current state is already what you want.
   79                 read -r current < "${file}"
   80 
   81                 # On some enclosures if you write 1 to fault, and read it back,
   82                 # it will return 2.  Treat all non-zero values as 1 for
   83                 # simplicity.
   84                 if [ "$current" != "0" ] ; then
   85                         current=1
   86                 fi
   87 
   88                 if [ "$current" != "$val" ] ; then
   89                         echo "$val" > "$file"
   90                         zed_log_msg "vdev $vdev set '$file' LED to $val"
   91                 else
   92                         break
   93                 fi
   94         done
   95 }
   96 
   97 # Fault LEDs for JBODs and NVMe drives are handled a little differently.
   98 #
   99 # On JBODs the fault LED is called 'fault' and on a path like this:
  100 #
  101 #   /sys/class/enclosure/0:0:1:0/SLOT 10/fault
  102 #
  103 # On NVMe it's called 'attention' and on a path like this:
  104 #
  105 #   /sys/bus/pci/slot/0/attention
  106 #
  107 # This function returns the full path to the fault LED file for a given
  108 # enclosure/slot directory.
  109 #
  110 path_to_led()
  111 {
  112         dir=$1
  113         if [ -f "$dir/fault" ] ; then
  114                 echo "$dir/fault"
  115         elif [ -f "$dir/attention" ] ; then
  116                 echo "$dir/attention"
  117         fi
  118 }
  119 
  120 state_to_val()
  121 {
  122         state="$1"
  123         case "$state" in
  124                 FAULTED|DEGRADED|UNAVAIL)
  125                         echo 1
  126                         ;;
  127                 ONLINE)
  128                         echo 0
  129                         ;;
  130                 *)
  131                         echo "invalid state: $state"
  132                         ;;
  133         esac
  134 }
  135 
  136 #
  137 # Given a nvme name like 'nvme0n1', pass back its slot directory
  138 # like "/sys/bus/pci/slots/0"
  139 #
  140 nvme_dev_to_slot()
  141 {
  142         dev="$1"
  143 
  144         # Get the address "0000:01:00.0"
  145         read -r address < "/sys/class/block/$dev/device/address"
  146 
  147         find /sys/bus/pci/slots -regex '.*/[0-9]+/address$' | \
  148                 while read -r sys_addr; do
  149                         read -r this_address < "$sys_addr"
  150 
  151                         # The format of address is a little different between
  152                         # /sys/class/block/$dev/device/address and
  153                         # /sys/bus/pci/slots/
  154                         #
  155                         # address=           "0000:01:00.0"
  156                         # this_address =     "0000:01:00"
  157                         #
  158                         if echo "$address" | grep -Eq ^"$this_address" ; then
  159                                 echo "${sys_addr%/*}"
  160                                 break
  161                         fi
  162                         done
  163 }
  164 
  165 
  166 # process_pool (pool)
  167 #
  168 # Iterate through a pool and set the vdevs' enclosure slot LEDs to
  169 # those vdevs' state.
  170 #
  171 # Arguments
  172 #   pool:       Pool name.
  173 #
  174 # Return
  175 #  0 on success, 3 on missing sysfs path
  176 #
  177 process_pool()
  178 {
  179         pool="$1"
  180 
  181         # The output will be the vdevs only (from "grep '/dev/'"):
  182         #
  183         #    U45     ONLINE       0     0     0   /dev/sdk          0
  184         #    U46     ONLINE       0     0     0   /dev/sdm          0
  185         #    U47     ONLINE       0     0     0   /dev/sdn          0
  186         #    U50     ONLINE       0     0     0  /dev/sdbn          0
  187         #
  188         ZPOOL_SCRIPTS_AS_ROOT=1 $ZPOOL status -c upath,fault_led "$pool" | grep '/dev/' | (
  189         rc=0
  190         while read -r vdev state _ _ _ therest; do
  191                 # Read out current LED value and path
  192                 # Get dev name (like 'sda')
  193                 dev=$(basename "$(echo "$therest" | awk '{print $(NF-1)}')")
  194                 vdev_enc_sysfs_path=$(realpath "/sys/class/block/$dev/device/enclosure_device"*)
  195                 if [ ! -d "$vdev_enc_sysfs_path" ] ; then
  196                         # This is not a JBOD disk, but it could be a PCI NVMe drive
  197                         vdev_enc_sysfs_path=$(nvme_dev_to_slot "$dev")
  198                 fi
  199 
  200                 current_val=$(echo "$therest" | awk '{print $NF}')
  201 
  202                 if [ "$current_val" != "0" ] ; then
  203                         current_val=1
  204                 fi
  205 
  206                 if [ -z "$vdev_enc_sysfs_path" ] ; then
  207                         # Skip anything with no sysfs LED entries
  208                         continue
  209                 fi
  210 
  211                 led_path=$(path_to_led "$vdev_enc_sysfs_path")
  212                 if [ ! -e "$led_path" ] ; then
  213                         rc=3
  214                         zed_log_msg "vdev $vdev '$led_path' doesn't exist"
  215                         continue
  216                 fi
  217 
  218                 val=$(state_to_val "$state")
  219 
  220                 if [ "$current_val" = "$val" ] ; then
  221                         # LED is already set correctly
  222                         continue
  223                 fi
  224 
  225                 if ! check_and_set_led "$led_path" "$val"; then
  226                         rc=3
  227                 fi
  228         done
  229         exit "$rc"; )
  230 }
  231 
  232 if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then
  233         # Got a statechange for an individual vdev
  234         val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
  235         vdev=$(basename "$ZEVENT_VDEV_PATH")
  236         ledpath=$(path_to_led "$ZEVENT_VDEV_ENC_SYSFS_PATH")
  237         check_and_set_led "$ledpath" "$val"
  238 else
  239         # Process the entire pool
  240         poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")
  241         process_pool "$poolname"
  242 fi

Cache object: 408220b377b6a356ff0e5fc7a9023555


[ 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.