numam-spdk/scripts/common.sh
Nick Connolly 5a21edf4e3 scripts: add autotest support for Windows
Source Windows specific definitions from common.sh. These adjust
uname to report the operating system as WSL, Msys or Cygwin and the
kernel name as Windows.  They also define kill() to invoke the SIGTERM
handler before causing a hard stop with TerminateProcess.

Adjust the ordering of the 'source' commands in autotest_common.sh so
that the config definitions are available when common.sh is loaded.
Define MAKE, MAKEFLAGS and HUGEMEM for Windows.

Signed-off-by: Nick Connolly <nick.connolly@mayadata.io>
Change-Id: I130b892ee55c925a0b033bda271a29133993afb7
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/7101
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
2021-06-08 08:19:32 +00:00

325 lines
7.8 KiB
Bash

# Common shell utility functions
# Check if PCI device is in PCI_ALLOWED and not in PCI_BLOCKED
# Env:
# if PCI_ALLOWED is empty assume device is allowed
# if PCI_BLOCKED is empty assume device is NOT blocked
# Params:
# $1 - PCI BDF
function pci_can_use() {
local i
# The '\ ' part is important
if [[ " $PCI_BLOCKED " =~ \ $1\ ]]; then
return 1
fi
if [[ -z "$PCI_ALLOWED" ]]; then
#no allow list specified, bind all devices
return 0
fi
for i in $PCI_ALLOWED; do
if [ "$i" == "$1" ]; then
return 0
fi
done
return 1
}
resolve_mod() {
local mod=$1 aliases=()
if aliases=($(modprobe -R "$mod")); then
echo "${aliases[0]}"
else
echo "unknown"
fi 2> /dev/null
}
cache_pci_init() {
local -gA pci_bus_cache
local -gA pci_ids_vendor
local -gA pci_ids_device
local -gA pci_bus_driver
local -gA pci_mod_driver
local -gA pci_mod_resolved
[[ -z ${pci_bus_cache[*]} || $CMD == reset ]] || return 1
pci_bus_cache=()
pci_bus_ids_vendor=()
pci_bus_ids_device=()
pci_bus_driver=()
pci_mod_driver=()
pci_mod_resolved=()
}
cache_pci() {
local pci=$1 class=$2 vendor=$3 device=$4 driver=$5 mod=$6
if [[ -n $class ]]; then
class=0x${class/0x/}
pci_bus_cache["$class"]="${pci_bus_cache["$class"]:+${pci_bus_cache["$class"]} }$pci"
fi
if [[ -n $vendor && -n $device ]]; then
vendor=0x${vendor/0x/} device=0x${device/0x/}
pci_bus_cache["$vendor:$device"]="${pci_bus_cache["$vendor:$device"]:+${pci_bus_cache["$vendor:$device"]} }$pci"
pci_ids_vendor["$pci"]=$vendor
pci_ids_device["$pci"]=$device
fi
if [[ -n $driver ]]; then
pci_bus_driver["$pci"]=$driver
fi
if [[ -n $mod ]]; then
pci_mod_driver["$pci"]=$mod
pci_mod_resolved["$pci"]=$(resolve_mod "$mod")
fi
}
cache_pci_bus_sysfs() {
[[ -e /sys/bus/pci/devices ]] || return 1
cache_pci_init || return 0
local pci
local class vendor device driver mod
for pci in /sys/bus/pci/devices/*; do
class=$(< "$pci/class") vendor=$(< "$pci/vendor") device=$(< "$pci/device") driver="" mod=""
if [[ -e $pci/driver ]]; then
driver=$(readlink -f "$pci/driver")
driver=${driver##*/}
else
driver=unbound
fi
if [[ -e $pci/modalias ]]; then
mod=$(< "$pci/modalias")
fi
cache_pci "${pci##*/}" "$class" "$vendor" "$device" "$driver" "$mod"
done
}
cache_pci_bus_lspci() {
hash lspci 2> /dev/null || return 1
cache_pci_init || return 0
local dev
while read -ra dev; do
dev=("${dev[@]//\"/}")
# lspci splits ls byte of the class (prog. interface) into a separate
# field if it's != 0. Look for it and normalize the value to fit with
# what kernel exposes under sysfs.
if [[ ${dev[*]} =~ -p([0-9]+) ]]; then
dev[1]+=${BASH_REMATCH[1]}
else
dev[1]+=00
fi
# pci class vendor device
cache_pci "${dev[@]::4}"
done < <(lspci -Dnmm)
}
cache_pci_bus_pciconf() {
hash pciconf 2> /dev/null || return 1
cache_pci_init || return 0
local class vd vendor device
local pci domain bus device function
while read -r pci class _ vd _; do
IFS=":" read -r domain bus device function _ <<< "${pci##*pci}"
pci=$(printf '%04x:%02x:%02x:%x' \
"$domain" "$bus" "$device" "$function")
class=$(printf '0x%06x' $((class)))
vendor=$(printf '0x%04x' $((vd & 0xffff)))
device=$(printf '0x%04x' $(((vd >> 16) & 0xffff)))
cache_pci "$pci" "$class" "$vendor" "$device"
done < <(pciconf -l)
}
cache_pci_bus() {
case "$(uname -s)" in
Linux) cache_pci_bus_lspci || cache_pci_bus_sysfs ;;
FreeBSD) cache_pci_bus_pciconf ;;
esac
}
iter_all_pci_sysfs() {
cache_pci_bus_sysfs || return 1
# default to class of the nvme devices
local find=${1:-0x010802} findx=$2
local pci pcis
[[ -n ${pci_bus_cache["$find"]} ]] || return 0
read -ra pcis <<< "${pci_bus_cache["$find"]}"
if ((findx)); then
printf '%s\n' "${pcis[@]::findx}"
else
printf '%s\n' "${pcis[@]}"
fi
}
# This function will ignore PCI PCI_ALLOWED and PCI_BLOCKED
function iter_all_pci_class_code() {
local class
local subclass
local progif
class="$(printf %02x $((0x$1)))"
subclass="$(printf %02x $((0x$2)))"
progif="$(printf %02x $((0x$3)))"
if hash lspci &> /dev/null; then
if [ "$progif" != "00" ]; then
lspci -mm -n -D \
| grep -i -- "-p${progif}" \
| awk -v cc="\"${class}${subclass}\"" -F " " \
'{if (cc ~ $2) print $1}' | tr -d '"'
else
lspci -mm -n -D \
| awk -v cc="\"${class}${subclass}\"" -F " " \
'{if (cc ~ $2) print $1}' | tr -d '"'
fi
elif hash pciconf &> /dev/null; then
local addr=($(pciconf -l | grep -i "class=0x${class}${subclass}${progif}" \
| cut -d$'\t' -f1 | sed -e 's/^[a-zA-Z0-9_]*@pci//g' | tr ':' ' '))
printf "%04x:%02x:%02x:%x\n" ${addr[0]} ${addr[1]} ${addr[2]} ${addr[3]}
elif iter_all_pci_sysfs "$(printf '0x%06x' $((0x$progif | 0x$subclass << 8 | 0x$class << 16)))"; then
:
else
echo "Missing PCI enumeration utility" >&2
exit 1
fi
}
# This function will ignore PCI PCI_ALLOWED and PCI_BLOCKED
function iter_all_pci_dev_id() {
local ven_id
local dev_id
ven_id="$(printf %04x $((0x$1)))"
dev_id="$(printf %04x $((0x$2)))"
if hash lspci &> /dev/null; then
lspci -mm -n -D | awk -v ven="\"$ven_id\"" -v dev="\"${dev_id}\"" -F " " \
'{if (ven ~ $3 && dev ~ $4) print $1}' | tr -d '"'
elif hash pciconf &> /dev/null; then
local addr=($(pciconf -l | grep -i "chip=0x${dev_id}${ven_id}" \
| cut -d$'\t' -f1 | sed -e 's/^[a-zA-Z0-9_]*@pci//g' | tr ':' ' '))
printf "%04x:%02x:%02x:%x\n" ${addr[0]} ${addr[1]} ${addr[2]} ${addr[3]}
elif iter_all_pci_sysfs "0x$ven_id:0x$dev_id"; then
:
else
echo "Missing PCI enumeration utility" >&2
exit 1
fi
}
function iter_pci_dev_id() {
local bdf=""
for bdf in $(iter_all_pci_dev_id "$@"); do
if pci_can_use "$bdf"; then
echo "$bdf"
fi
done
}
# This function will filter out PCI devices using PCI_ALLOWED and PCI_BLOCKED
# See function pci_can_use()
function iter_pci_class_code() {
local bdf=""
for bdf in $(iter_all_pci_class_code "$@"); do
if pci_can_use "$bdf"; then
echo "$bdf"
fi
done
}
function nvme_in_userspace() {
# Check used drivers. If it's not vfio-pci or uio-pci-generic
# then most likely PCI_ALLOWED option was used for setup.sh
# and we do not want to use that disk.
local bdf bdfs
local nvmes
if [[ -n ${pci_bus_cache["0x010802"]} ]]; then
nvmes=(${pci_bus_cache["0x010802"]})
else
nvmes=($(iter_pci_class_code 01 08 02))
fi
for bdf in "${nvmes[@]}"; do
if [[ -e /sys/bus/pci/drivers/nvme/$bdf ]] \
|| [[ $(uname -s) == FreeBSD && $(pciconf -l "pci${bdf/./:}") == nvme* ]]; then
continue
fi
bdfs+=("$bdf")
done
((${#bdfs[@]})) || return 1
printf '%s\n' "${bdfs[@]}"
}
cmp_versions() {
local ver1 ver1_l
local ver2 ver2_l
IFS=".-:" read -ra ver1 <<< "$1"
IFS=".-:" read -ra ver2 <<< "$3"
local op=$2
ver1_l=${#ver1[@]}
ver2_l=${#ver2[@]}
local lt=0 gt=0 eq=0 v
case "$op" in
"<") : $((eq = gt = 1)) ;;
">") : $((eq = lt = 1)) ;;
"<=") : $((gt = 1)) ;;
">=") : $((lt = 1)) ;;
"==") : $((lt = gt = 1)) ;;
esac
decimal() (
local d=${1,,}
if [[ $d =~ ^[0-9]+$ ]]; then
echo $((10#$d))
elif [[ $d =~ ^0x || $d =~ ^[a-f0-9]+$ ]]; then
d=${d/0x/}
echo $((0x$d))
else
echo 0
fi
)
for ((v = 0; v < (ver1_l > ver2_l ? ver1_l : ver2_l); v++)); do
ver1[v]=$(decimal "${ver1[v]}")
ver2[v]=$(decimal "${ver2[v]}")
((ver1[v] > ver2[v])) && return "$gt"
((ver1[v] < ver2[v])) && return "$lt"
done
[[ ${ver1[*]} == "${ver2[*]}" ]] && return "$eq"
}
lt() { cmp_versions "$1" "<" "$2"; }
gt() { cmp_versions "$1" ">" "$2"; }
le() { cmp_versions "$1" "<=" "$2"; }
ge() { cmp_versions "$1" ">=" "$2"; }
eq() { cmp_versions "$1" "==" "$2"; }
neq() { ! eq "$1" "$2"; }
if [[ -e "$CONFIG_WPDK_DIR/bin/wpdk_common.sh" ]]; then
# Adjust uname to report the operating system as WSL, Msys or Cygwin
# and the kernel name as Windows. Define kill() to invoke the SIGTERM
# handler before causing a hard stop with TerminateProcess.
source "$CONFIG_WPDK_DIR/bin/wpdk_common.sh"
fi