xref: /spdk/scripts/common.sh (revision cb7af50cfdf0f6fa3c3b3755969b8d386cbaca34)
1eb53c232Spaul luse#  SPDX-License-Identifier: BSD-3-Clause
2eb53c232Spaul luse#  Copyright (C) 2018 Intel Corporation
3eb53c232Spaul luse#  All rights reserved.
4eb53c232Spaul luse#
5eb53c232Spaul luse
6f0c20934SDaniel Verkamp# Common shell utility functions
7f0c20934SDaniel Verkamp
8a1280c98SJim Harris# Check if PCI device is in PCI_ALLOWED and not in PCI_BLOCKED
95de43a75SPawel Wodkowski# Env:
10a1280c98SJim Harris# if PCI_ALLOWED is empty assume device is allowed
11a1280c98SJim Harris# if PCI_BLOCKED is empty assume device is NOT blocked
125de43a75SPawel Wodkowski# Params:
135de43a75SPawel Wodkowski# $1 - PCI BDF
14*cb7af50cSMichal Berger
15*cb7af50cSMichal Bergershopt -s extglob
16*cb7af50cSMichal Berger
17ad32c7b8SPawel Wodkowskifunction pci_can_use() {
185de43a75SPawel Wodkowski	local i
195de43a75SPawel Wodkowski
205de43a75SPawel Wodkowski	# The '\ ' part is important
21a1280c98SJim Harris	if [[ " $PCI_BLOCKED " =~ \ $1\  ]]; then
225de43a75SPawel Wodkowski		return 1
235de43a75SPawel Wodkowski	fi
245de43a75SPawel Wodkowski
25a1280c98SJim Harris	if [[ -z "$PCI_ALLOWED" ]]; then
26a1280c98SJim Harris		#no allow list specified, bind all devices
275de43a75SPawel Wodkowski		return 0
285de43a75SPawel Wodkowski	fi
295de43a75SPawel Wodkowski
30a1280c98SJim Harris	for i in $PCI_ALLOWED; do
315de43a75SPawel Wodkowski		if [ "$i" == "$1" ]; then
325de43a75SPawel Wodkowski			return 0
335de43a75SPawel Wodkowski		fi
345de43a75SPawel Wodkowski	done
355de43a75SPawel Wodkowski
365de43a75SPawel Wodkowski	return 1
375de43a75SPawel Wodkowski}
385de43a75SPawel Wodkowski
399b3773dbSMichal Bergerresolve_mod() {
409b3773dbSMichal Berger	local mod=$1 aliases=()
419b3773dbSMichal Berger
429b3773dbSMichal Berger	if aliases=($(modprobe -R "$mod")); then
439b3773dbSMichal Berger		echo "${aliases[0]}"
449b3773dbSMichal Berger	else
459b3773dbSMichal Berger		echo "unknown"
469b3773dbSMichal Berger	fi 2> /dev/null
479b3773dbSMichal Berger}
489b3773dbSMichal Berger
4936e573fcSMichal Bergercache_pci_init() {
5036e573fcSMichal Berger	local -gA pci_bus_cache
515a436f0cSMichal Berger	local -gA pci_ids_vendor
525a436f0cSMichal Berger	local -gA pci_ids_device
535f61a0c9SMichal Berger	local -gA pci_bus_driver
549b3773dbSMichal Berger	local -gA pci_mod_driver
559b3773dbSMichal Berger	local -gA pci_mod_resolved
56c5c065e9SMichal Berger	local -gA pci_iommu_groups
57c5c065e9SMichal Berger	local -ga iommu_groups
5836e573fcSMichal Berger
5936e573fcSMichal Berger	[[ -z ${pci_bus_cache[*]} || $CMD == reset ]] || return 1
6036e573fcSMichal Berger
6136e573fcSMichal Berger	pci_bus_cache=()
625a436f0cSMichal Berger	pci_bus_ids_vendor=()
635a436f0cSMichal Berger	pci_bus_ids_device=()
645f61a0c9SMichal Berger	pci_bus_driver=()
659b3773dbSMichal Berger	pci_mod_driver=()
669b3773dbSMichal Berger	pci_mod_resolved=()
67c5c065e9SMichal Berger	pci_iommu_groups=()
68c5c065e9SMichal Berger	iommu_groups=()
6936e573fcSMichal Berger}
7036e573fcSMichal Berger
7136e573fcSMichal Bergercache_pci() {
729b3773dbSMichal Berger	local pci=$1 class=$2 vendor=$3 device=$4 driver=$5 mod=$6
7336e573fcSMichal Berger
7436e573fcSMichal Berger	if [[ -n $class ]]; then
75844c8ec3SMichal Berger		class=0x${class/0x/}
7636e573fcSMichal Berger		pci_bus_cache["$class"]="${pci_bus_cache["$class"]:+${pci_bus_cache["$class"]} }$pci"
7736e573fcSMichal Berger	fi
7836e573fcSMichal Berger	if [[ -n $vendor && -n $device ]]; then
79844c8ec3SMichal Berger		vendor=0x${vendor/0x/} device=0x${device/0x/}
8036e573fcSMichal Berger		pci_bus_cache["$vendor:$device"]="${pci_bus_cache["$vendor:$device"]:+${pci_bus_cache["$vendor:$device"]} }$pci"
815a436f0cSMichal Berger
825a436f0cSMichal Berger		pci_ids_vendor["$pci"]=$vendor
835a436f0cSMichal Berger		pci_ids_device["$pci"]=$device
8436e573fcSMichal Berger	fi
855f61a0c9SMichal Berger	if [[ -n $driver ]]; then
865f61a0c9SMichal Berger		pci_bus_driver["$pci"]=$driver
875f61a0c9SMichal Berger	fi
889b3773dbSMichal Berger	if [[ -n $mod ]]; then
899b3773dbSMichal Berger		pci_mod_driver["$pci"]=$mod
909b3773dbSMichal Berger		pci_mod_resolved["$pci"]=$(resolve_mod "$mod")
919b3773dbSMichal Berger	fi
92c5c065e9SMichal Berger
93c5c065e9SMichal Berger	cache_pci_iommu_group "$pci"
94c5c065e9SMichal Berger}
95c5c065e9SMichal Berger
96c5c065e9SMichal Bergercache_iommu_group() {
97c5c065e9SMichal Berger	local iommu_group=$1 pcis=() pci
98c5c065e9SMichal Berger
99c5c065e9SMichal Berger	[[ -e /sys/kernel/iommu_groups/$iommu_group/type ]] || return 0
100c5c065e9SMichal Berger
101c5c065e9SMichal Berger	local -n _iommu_group_ref=_iommu_group_$iommu_group
102c5c065e9SMichal Berger
103c5c065e9SMichal Berger	iommu_groups[iommu_group]="_iommu_group_${iommu_group}[@]"
104c5c065e9SMichal Berger
105c5c065e9SMichal Berger	for pci in "/sys/kernel/iommu_groups/$iommu_group/devices/"*; do
106c5c065e9SMichal Berger		pci=${pci##*/}
107c5c065e9SMichal Berger		[[ -n ${pci_iommu_groups["$pci"]} ]] && continue
108c5c065e9SMichal Berger		pci_iommu_groups["$pci"]=$iommu_group
109c5c065e9SMichal Berger		_iommu_group_ref+=("$pci")
110c5c065e9SMichal Berger	done
111c5c065e9SMichal Berger
112c5c065e9SMichal Berger}
113c5c065e9SMichal Berger
114c5c065e9SMichal Bergercache_pci_iommu_group() {
115c5c065e9SMichal Berger	local pci=$1 iommu_group
116c5c065e9SMichal Berger
117c5c065e9SMichal Berger	[[ -e /sys/bus/pci/devices/$pci/iommu_group ]] || return 0
118c5c065e9SMichal Berger
119c5c065e9SMichal Berger	iommu_group=$(readlink -f "/sys/bus/pci/devices/$pci/iommu_group")
120c5c065e9SMichal Berger	iommu_group=${iommu_group##*/}
121c5c065e9SMichal Berger
122c5c065e9SMichal Berger	cache_iommu_group "$iommu_group"
12336e573fcSMichal Berger}
12436e573fcSMichal Berger
1253ac0a6edSMichal Bergeris_iommu_enabled() {
1263ac0a6edSMichal Berger	[[ -e /sys/kernel/iommu_groups/0 ]] && return 0
1273ac0a6edSMichal Berger	[[ -e /sys/module/vfio/parameters/enable_unsafe_noiommu_mode ]] || return 1
1283ac0a6edSMichal Berger	[[ $(< /sys/module/vfio/parameters/enable_unsafe_noiommu_mode) == Y ]]
1293ac0a6edSMichal Berger}
1303ac0a6edSMichal Berger
13136e573fcSMichal Bergercache_pci_bus_sysfs() {
13236e573fcSMichal Berger	[[ -e /sys/bus/pci/devices ]] || return 1
13336e573fcSMichal Berger
13436e573fcSMichal Berger	cache_pci_init || return 0
13536e573fcSMichal Berger
13636e573fcSMichal Berger	local pci
1379b3773dbSMichal Berger	local class vendor device driver mod
13836e573fcSMichal Berger
13936e573fcSMichal Berger	for pci in /sys/bus/pci/devices/*; do
1409b3773dbSMichal Berger		class=$(< "$pci/class") vendor=$(< "$pci/vendor") device=$(< "$pci/device") driver="" mod=""
1419ad576c6SMichal Berger		driver=$(get_pci_driver_sysfs "${pci##*/}")
1429b3773dbSMichal Berger		if [[ -e $pci/modalias ]]; then
1439b3773dbSMichal Berger			mod=$(< "$pci/modalias")
1449b3773dbSMichal Berger		fi
1459b3773dbSMichal Berger		cache_pci "${pci##*/}" "$class" "$vendor" "$device" "$driver" "$mod"
14636e573fcSMichal Berger	done
14736e573fcSMichal Berger}
14836e573fcSMichal Berger
14936e573fcSMichal Bergercache_pci_bus_lspci() {
15036e573fcSMichal Berger	hash lspci 2> /dev/null || return 1
15136e573fcSMichal Berger
15236e573fcSMichal Berger	cache_pci_init || return 0
15336e573fcSMichal Berger
15436e573fcSMichal Berger	local dev
15536e573fcSMichal Berger	while read -ra dev; do
15636e573fcSMichal Berger		dev=("${dev[@]//\"/}")
15736e573fcSMichal Berger		# lspci splits ls byte of the class (prog. interface) into a separate
15836e573fcSMichal Berger		# field if it's != 0. Look for it and normalize the value to fit with
15936e573fcSMichal Berger		# what kernel exposes under sysfs.
16036e573fcSMichal Berger		if [[ ${dev[*]} =~ -p([0-9]+) ]]; then
16136e573fcSMichal Berger			dev[1]+=${BASH_REMATCH[1]}
16236e573fcSMichal Berger		else
16336e573fcSMichal Berger			dev[1]+=00
16436e573fcSMichal Berger		fi
1659ad576c6SMichal Berger		# pci class vendor device driver
1669ad576c6SMichal Berger		# lspci supports driver listing only under Linux, however, it's not
1679ad576c6SMichal Berger		# included when specific display mode (i.e. -mm) is in use, even if
1689ad576c6SMichal Berger		# extra -k is slapped on the cmdline. So with that in mind, just
1699ad576c6SMichal Berger		# get that info from sysfs.
1709ad576c6SMichal Berger		cache_pci "${dev[@]::4}" "$(get_pci_driver_sysfs "${dev[0]}")"
17136e573fcSMichal Berger	done < <(lspci -Dnmm)
17236e573fcSMichal Berger}
17336e573fcSMichal Berger
17436e573fcSMichal Bergercache_pci_bus_pciconf() {
17536e573fcSMichal Berger	hash pciconf 2> /dev/null || return 1
17636e573fcSMichal Berger
17736e573fcSMichal Berger	cache_pci_init || return 0
17836e573fcSMichal Berger
1797201d0e6SMichal Berger	local class vendor device
1807201d0e6SMichal Berger	local pci pci_info
1817201d0e6SMichal Berger	local chip driver
18236e573fcSMichal Berger
1837201d0e6SMichal Berger	while read -r pci pci_info; do
1847201d0e6SMichal Berger		driver=${pci%@*}
1852635e73dSMichal Berger		pci=${pci#*:} pci=${pci%:} # E.g.: nvme0@pci0:0:16:0: -> 0:16:0
1867201d0e6SMichal Berger		source <(echo "$pci_info")
1877201d0e6SMichal Berger		# pciconf under FreeBSD 13.1 provides vendor and device IDs in its
1887201d0e6SMichal Berger		# output under separate, dedicated fields. For 12.x they need to
1897201d0e6SMichal Berger		# be extracted from the chip field.
1907201d0e6SMichal Berger		if [[ -n $chip ]]; then
1917201d0e6SMichal Berger			vendor=$(printf '0x%04x' $((chip & 0xffff)))
1927201d0e6SMichal Berger			device=$(printf '0x%04x' $(((chip >> 16) & 0xffff)))
1937201d0e6SMichal Berger		fi
1947201d0e6SMichal Berger		cache_pci "$pci" "$class" "$vendor" "$device" "$driver"
19536e573fcSMichal Berger	done < <(pciconf -l)
19636e573fcSMichal Berger}
19736e573fcSMichal Berger
1989ad576c6SMichal Bergerget_pci_driver_sysfs() {
1999ad576c6SMichal Berger	local pci=/sys/bus/pci/devices/$1 driver
2009ad576c6SMichal Berger
2019ad576c6SMichal Berger	if [[ -e $pci/driver ]]; then
2029ad576c6SMichal Berger		driver=$(readlink -f "$pci/driver") driver=${driver##*/}
2039ad576c6SMichal Berger	fi
2049ad576c6SMichal Berger	echo "$driver"
2059ad576c6SMichal Berger}
2069ad576c6SMichal Berger
20736e573fcSMichal Bergercache_pci_bus() {
20836e573fcSMichal Berger	case "$(uname -s)" in
20936e573fcSMichal Berger		Linux) cache_pci_bus_lspci || cache_pci_bus_sysfs ;;
21036e573fcSMichal Berger		FreeBSD) cache_pci_bus_pciconf ;;
21136e573fcSMichal Berger	esac
21236e573fcSMichal Berger}
21336e573fcSMichal Berger
21436e573fcSMichal Bergeriter_all_pci_sysfs() {
21536e573fcSMichal Berger	cache_pci_bus_sysfs || return 1
21636e573fcSMichal Berger
21736e573fcSMichal Berger	# default to class of the nvme devices
21836e573fcSMichal Berger	local find=${1:-0x010802} findx=$2
21936e573fcSMichal Berger	local pci pcis
22036e573fcSMichal Berger
22136e573fcSMichal Berger	[[ -n ${pci_bus_cache["$find"]} ]] || return 0
22236e573fcSMichal Berger	read -ra pcis <<< "${pci_bus_cache["$find"]}"
22336e573fcSMichal Berger
22436e573fcSMichal Berger	if ((findx)); then
22536e573fcSMichal Berger		printf '%s\n' "${pcis[@]::findx}"
22636e573fcSMichal Berger	else
22736e573fcSMichal Berger		printf '%s\n' "${pcis[@]}"
22836e573fcSMichal Berger	fi
22936e573fcSMichal Berger}
23036e573fcSMichal Berger
231a1280c98SJim Harris# This function will ignore PCI PCI_ALLOWED and PCI_BLOCKED
232ad32c7b8SPawel Wodkowskifunction iter_all_pci_class_code() {
233074df1d8SPawel Kaminski	local class
234074df1d8SPawel Kaminski	local subclass
235074df1d8SPawel Kaminski	local progif
236074df1d8SPawel Kaminski	class="$(printf %02x $((0x$1)))"
237074df1d8SPawel Kaminski	subclass="$(printf %02x $((0x$2)))"
238074df1d8SPawel Kaminski	progif="$(printf %02x $((0x$3)))"
239f0c20934SDaniel Verkamp
240f0c20934SDaniel Verkamp	if hash lspci &> /dev/null; then
241f0c20934SDaniel Verkamp		if [ "$progif" != "00" ]; then
242844c8ec3SMichal Berger			lspci -mm -n -D \
243844c8ec3SMichal Berger				| grep -i -- "-p${progif}" \
244844c8ec3SMichal Berger				| awk -v cc="\"${class}${subclass}\"" -F " " \
245f0c20934SDaniel Verkamp					'{if (cc ~ $2) print $1}' | tr -d '"'
246f0c20934SDaniel Verkamp		else
247844c8ec3SMichal Berger			lspci -mm -n -D \
248844c8ec3SMichal Berger				| awk -v cc="\"${class}${subclass}\"" -F " " \
249f0c20934SDaniel Verkamp					'{if (cc ~ $2) print $1}' | tr -d '"'
250f0c20934SDaniel Verkamp		fi
251f0c20934SDaniel Verkamp	elif hash pciconf &> /dev/null; then
252844c8ec3SMichal Berger		local addr=($(pciconf -l | grep -i "class=0x${class}${subclass}${progif}" \
253844c8ec3SMichal Berger			| cut -d$'\t' -f1 | sed -e 's/^[a-zA-Z0-9_]*@pci//g' | tr ':' ' '))
2547201d0e6SMichal Berger		echo "${addr[0]}:${addr[1]}:${addr[2]}:${addr[3]}"
25536e573fcSMichal Berger	elif iter_all_pci_sysfs "$(printf '0x%06x' $((0x$progif | 0x$subclass << 8 | 0x$class << 16)))"; then
25636e573fcSMichal Berger		:
257ad32c7b8SPawel Wodkowski	else
258f2bfad59SLiu Xiaodong		echo "Missing PCI enumeration utility" >&2
259ad32c7b8SPawel Wodkowski		exit 1
260ad32c7b8SPawel Wodkowski	fi
261ad32c7b8SPawel Wodkowski}
262ad32c7b8SPawel Wodkowski
263a1280c98SJim Harris# This function will ignore PCI PCI_ALLOWED and PCI_BLOCKED
264ad32c7b8SPawel Wodkowskifunction iter_all_pci_dev_id() {
265074df1d8SPawel Kaminski	local ven_id
266074df1d8SPawel Kaminski	local dev_id
267074df1d8SPawel Kaminski	ven_id="$(printf %04x $((0x$1)))"
268074df1d8SPawel Kaminski	dev_id="$(printf %04x $((0x$2)))"
269ad32c7b8SPawel Wodkowski
270ad32c7b8SPawel Wodkowski	if hash lspci &> /dev/null; then
271ad32c7b8SPawel Wodkowski		lspci -mm -n -D | awk -v ven="\"$ven_id\"" -v dev="\"${dev_id}\"" -F " " \
272ad32c7b8SPawel Wodkowski			'{if (ven ~ $3 && dev ~ $4) print $1}' | tr -d '"'
273ad32c7b8SPawel Wodkowski	elif hash pciconf &> /dev/null; then
2747201d0e6SMichal Berger		local addr=($(pciconf -l | grep -iE "chip=0x${dev_id}${ven_id}|vendor=0x$ven_id device=0x$dev_id" \
275844c8ec3SMichal Berger			| cut -d$'\t' -f1 | sed -e 's/^[a-zA-Z0-9_]*@pci//g' | tr ':' ' '))
2767201d0e6SMichal Berger		echo "${addr[0]}:${addr[1]}:${addr[2]}:${addr[3]}"
27736e573fcSMichal Berger	elif iter_all_pci_sysfs "0x$ven_id:0x$dev_id"; then
27836e573fcSMichal Berger		:
279f0c20934SDaniel Verkamp	else
280f2bfad59SLiu Xiaodong		echo "Missing PCI enumeration utility" >&2
281f0c20934SDaniel Verkamp		exit 1
282f0c20934SDaniel Verkamp	fi
283f0c20934SDaniel Verkamp}
284f0c20934SDaniel Verkamp
285f0c20934SDaniel Verkampfunction iter_pci_dev_id() {
286ad32c7b8SPawel Wodkowski	local bdf=""
287f0c20934SDaniel Verkamp
288ad32c7b8SPawel Wodkowski	for bdf in $(iter_all_pci_dev_id "$@"); do
289ad32c7b8SPawel Wodkowski		if pci_can_use "$bdf"; then
290ad32c7b8SPawel Wodkowski			echo "$bdf"
291f0c20934SDaniel Verkamp		fi
292ad32c7b8SPawel Wodkowski	done
293ad32c7b8SPawel Wodkowski}
294ad32c7b8SPawel Wodkowski
295a1280c98SJim Harris# This function will filter out PCI devices using PCI_ALLOWED and PCI_BLOCKED
296ad32c7b8SPawel Wodkowski# See function pci_can_use()
297ad32c7b8SPawel Wodkowskifunction iter_pci_class_code() {
298ad32c7b8SPawel Wodkowski	local bdf=""
299ad32c7b8SPawel Wodkowski
300ad32c7b8SPawel Wodkowski	for bdf in $(iter_all_pci_class_code "$@"); do
301ad32c7b8SPawel Wodkowski		if pci_can_use "$bdf"; then
302ad32c7b8SPawel Wodkowski			echo "$bdf"
303ad32c7b8SPawel Wodkowski		fi
304ad32c7b8SPawel Wodkowski	done
305f0c20934SDaniel Verkamp}
30635babadeSMichal Berger
30735babadeSMichal Bergerfunction nvme_in_userspace() {
30835babadeSMichal Berger	# Check used drivers. If it's not vfio-pci or uio-pci-generic
309a1280c98SJim Harris	# then most likely PCI_ALLOWED option was used for setup.sh
31035babadeSMichal Berger	# and we do not want to use that disk.
31135babadeSMichal Berger
31235babadeSMichal Berger	local bdf bdfs
31335babadeSMichal Berger	local nvmes
31435babadeSMichal Berger
31535babadeSMichal Berger	if [[ -n ${pci_bus_cache["0x010802"]} ]]; then
31635babadeSMichal Berger		nvmes=(${pci_bus_cache["0x010802"]})
31735babadeSMichal Berger	else
31835babadeSMichal Berger		nvmes=($(iter_pci_class_code 01 08 02))
31935babadeSMichal Berger	fi
32035babadeSMichal Berger
32135babadeSMichal Berger	for bdf in "${nvmes[@]}"; do
32235babadeSMichal Berger		if [[ -e /sys/bus/pci/drivers/nvme/$bdf ]] \
32313d01bedSMichal Berger			|| [[ $(uname -s) == FreeBSD && $(pciconf -l "pci${bdf/./:}") == nvme* ]]; then
32435babadeSMichal Berger			continue
32535babadeSMichal Berger		fi
32635babadeSMichal Berger		bdfs+=("$bdf")
32735babadeSMichal Berger	done
32835babadeSMichal Berger	((${#bdfs[@]})) || return 1
32935babadeSMichal Berger	printf '%s\n' "${bdfs[@]}"
33035babadeSMichal Berger}
33177c4d0f6SMichal Berger
33286eadb4dSMichal Bergercmp_versions() {
33377c4d0f6SMichal Berger	local ver1 ver1_l
33477c4d0f6SMichal Berger	local ver2 ver2_l
33577c4d0f6SMichal Berger
33677c4d0f6SMichal Berger	IFS=".-:" read -ra ver1 <<< "$1"
33777c4d0f6SMichal Berger	IFS=".-:" read -ra ver2 <<< "$3"
33877c4d0f6SMichal Berger	local op=$2
33977c4d0f6SMichal Berger
34077c4d0f6SMichal Berger	ver1_l=${#ver1[@]}
34177c4d0f6SMichal Berger	ver2_l=${#ver2[@]}
34277c4d0f6SMichal Berger
34377c4d0f6SMichal Berger	local lt=0 gt=0 eq=0 v
34477c4d0f6SMichal Berger	case "$op" in
34577c4d0f6SMichal Berger		"<") : $((eq = gt = 1)) ;;
34677c4d0f6SMichal Berger		">") : $((eq = lt = 1)) ;;
34777c4d0f6SMichal Berger		"<=") : $((gt = 1)) ;;
34877c4d0f6SMichal Berger		">=") : $((lt = 1)) ;;
34977c4d0f6SMichal Berger		"==") : $((lt = gt = 1)) ;;
35077c4d0f6SMichal Berger	esac
35177c4d0f6SMichal Berger
35277c4d0f6SMichal Berger	decimal() (
35377c4d0f6SMichal Berger		local d=${1,,}
35477c4d0f6SMichal Berger		if [[ $d =~ ^[0-9]+$ ]]; then
35577c4d0f6SMichal Berger			echo $((10#$d))
35677c4d0f6SMichal Berger		elif [[ $d =~ ^0x || $d =~ ^[a-f0-9]+$ ]]; then
35777c4d0f6SMichal Berger			d=${d/0x/}
35877c4d0f6SMichal Berger			echo $((0x$d))
35977c4d0f6SMichal Berger		else
36077c4d0f6SMichal Berger			echo 0
36177c4d0f6SMichal Berger		fi
36277c4d0f6SMichal Berger	)
36377c4d0f6SMichal Berger
36477c4d0f6SMichal Berger	for ((v = 0; v < (ver1_l > ver2_l ? ver1_l : ver2_l); v++)); do
36577c4d0f6SMichal Berger		ver1[v]=$(decimal "${ver1[v]}")
36677c4d0f6SMichal Berger		ver2[v]=$(decimal "${ver2[v]}")
36777c4d0f6SMichal Berger		((ver1[v] > ver2[v])) && return "$gt"
36877c4d0f6SMichal Berger		((ver1[v] < ver2[v])) && return "$lt"
36977c4d0f6SMichal Berger	done
37077c4d0f6SMichal Berger	[[ ${ver1[*]} == "${ver2[*]}" ]] && return "$eq"
37177c4d0f6SMichal Berger}
37277c4d0f6SMichal Berger
37386eadb4dSMichal Bergerlt() { cmp_versions "$1" "<" "$2"; }
37486eadb4dSMichal Bergergt() { cmp_versions "$1" ">" "$2"; }
37586eadb4dSMichal Bergerle() { cmp_versions "$1" "<=" "$2"; }
37686eadb4dSMichal Bergerge() { cmp_versions "$1" ">=" "$2"; }
37786eadb4dSMichal Bergereq() { cmp_versions "$1" "==" "$2"; }
37877c4d0f6SMichal Bergerneq() { ! eq "$1" "$2"; }
3795a21edf4SNick Connolly
38076f840c0SMichal Bergerblock_in_use() {
38173517575SMichal Berger	local block=$1 pt
38276f840c0SMichal Berger	# Skip devices that are in use - simple blkid it to see if
38376f840c0SMichal Berger	# there's any metadata (pt, fs, etc.) present on the drive.
38476f840c0SMichal Berger	# FIXME: Special case to ignore atari as a potential false
38576f840c0SMichal Berger	# positive:
38676f840c0SMichal Berger	# https://github.com/spdk/spdk/issues/2079
38776f840c0SMichal Berger	# Devices with SPDK's GPT part type are not considered to
38876f840c0SMichal Berger	# be in use.
38976f840c0SMichal Berger
39076f840c0SMichal Berger	if "$rootdir/scripts/spdk-gpt.py" "$block"; then
39176f840c0SMichal Berger		return 1
39276f840c0SMichal Berger	fi
39376f840c0SMichal Berger
39473517575SMichal Berger	if ! pt=$(blkid -s PTTYPE -o value "/dev/${block##*/}"); then
39576f840c0SMichal Berger		return 1
39673517575SMichal Berger	elif [[ $pt == atari ]]; then
39776f840c0SMichal Berger		return 1
39876f840c0SMichal Berger	fi
39976f840c0SMichal Berger
400c733cd68STomasz Zawadzki	# Devices used in SPDK tests always create GPT partitions
401c733cd68STomasz Zawadzki	# with label containing SPDK_TEST string. Such devices were
402c733cd68STomasz Zawadzki	# part of the tests before, so are not considered in use.
403c733cd68STomasz Zawadzki	if [[ $pt == gpt ]] && parted "/dev/${block##*/}" -ms print | grep -q "SPDK_TEST"; then
404c733cd68STomasz Zawadzki		return 1
405c733cd68STomasz Zawadzki	fi
406c733cd68STomasz Zawadzki
40776f840c0SMichal Berger	return 0
40876f840c0SMichal Berger}
40976f840c0SMichal Berger
4103a39d90bSJim Harrisget_spdk_gpt_old() {
4113a39d90bSJim Harris	local spdk_guid
4123a39d90bSJim Harris
4133a39d90bSJim Harris	[[ -e $rootdir/module/bdev/gpt/gpt.h ]] || return 1
4143a39d90bSJim Harris
4153a39d90bSJim Harris	GPT_H="$rootdir/module/bdev/gpt/gpt.h"
4163a39d90bSJim Harris	IFS="()" read -r _ spdk_guid _ < <(grep -w SPDK_GPT_PART_TYPE_GUID_OLD "$GPT_H")
4173a39d90bSJim Harris	spdk_guid=${spdk_guid//, /-} spdk_guid=${spdk_guid//0x/}
4183a39d90bSJim Harris
4193a39d90bSJim Harris	echo "$spdk_guid"
4203a39d90bSJim Harris}
4213a39d90bSJim Harris
422b7947268SMichal Bergerget_spdk_gpt() {
423b7947268SMichal Berger	local spdk_guid
424b7947268SMichal Berger
425b7947268SMichal Berger	[[ -e $rootdir/module/bdev/gpt/gpt.h ]] || return 1
426b7947268SMichal Berger
4273a39d90bSJim Harris	GPT_H="$rootdir/module/bdev/gpt/gpt.h"
4283a39d90bSJim Harris	IFS="()" read -r _ spdk_guid _ < <(grep -w SPDK_GPT_PART_TYPE_GUID "$GPT_H")
429b7947268SMichal Berger	spdk_guid=${spdk_guid//, /-} spdk_guid=${spdk_guid//0x/}
430b7947268SMichal Berger
431b7947268SMichal Berger	echo "$spdk_guid"
432b7947268SMichal Berger}
433b7947268SMichal Berger
4344f8177b5SMichal Bergermap_supported_devices() {
4357014f640SMichal Berger	local type=${1^^}
4364f8177b5SMichal Berger	local ids dev_types dev_type dev_id bdf bdfs vmd _vmd
4374f8177b5SMichal Berger
4384f8177b5SMichal Berger	local -gA nvme_d
4394f8177b5SMichal Berger	local -gA ioat_d dsa_d iaa_d
4404f8177b5SMichal Berger	local -gA virtio_d
4414f8177b5SMichal Berger	local -gA vmd_d nvme_vmd_d vmd_nvme_d vmd_nvme_count
4424f8177b5SMichal Berger	local -gA all_devices_d types_d all_devices_type_d
4434f8177b5SMichal Berger
4444f8177b5SMichal Berger	ids+="PCI_DEVICE_ID_INTEL_IOAT" dev_types+="IOAT"
4454f8177b5SMichal Berger	ids+="|PCI_DEVICE_ID_INTEL_DSA" dev_types+="|DSA"
4464f8177b5SMichal Berger	ids+="|PCI_DEVICE_ID_INTEL_IAA" dev_types+="|IAA"
4474f8177b5SMichal Berger	ids+="|PCI_DEVICE_ID_VIRTIO" dev_types+="|VIRTIO"
4484f8177b5SMichal Berger	ids+="|PCI_DEVICE_ID_INTEL_VMD" dev_types+="|VMD"
4494f8177b5SMichal Berger	ids+="|SPDK_PCI_CLASS_NVME" dev_types+="|NVME"
4504f8177b5SMichal Berger
4514f8177b5SMichal Berger	[[ -e $rootdir/include/spdk/pci_ids.h ]] || return 1
4524f8177b5SMichal Berger
4534f8177b5SMichal Berger	((${#pci_bus_cache[@]} == 0)) && cache_pci_bus
4544f8177b5SMichal Berger
4554f8177b5SMichal Berger	while read -r _ dev_type dev_id; do
4567014f640SMichal Berger		[[ $dev_type == *$type* ]] || continue
4574f8177b5SMichal Berger		bdfs=(${pci_bus_cache["0x8086:$dev_id"]})
4584f8177b5SMichal Berger		[[ $dev_type == *NVME* ]] && bdfs=(${pci_bus_cache["$dev_id"]})
4594f8177b5SMichal Berger		[[ $dev_type == *VIRT* ]] && bdfs=(${pci_bus_cache["0x1af4:$dev_id"]})
4604f8177b5SMichal Berger		[[ $dev_type =~ ($dev_types) ]] && dev_type=${BASH_REMATCH[1],,}
4614f8177b5SMichal Berger		types_d["$dev_type"]=1
4624f8177b5SMichal Berger		for bdf in "${bdfs[@]}"; do
4634f8177b5SMichal Berger			eval "${dev_type}_d[$bdf]=0"
4644f8177b5SMichal Berger			all_devices_d["$bdf"]=0
4654f8177b5SMichal Berger			all_devices_type_d["$bdf"]=$dev_type
4664f8177b5SMichal Berger		done
4674f8177b5SMichal Berger	done < <(grep -E "$ids" "$rootdir/include/spdk/pci_ids.h")
4684f8177b5SMichal Berger
4694f8177b5SMichal Berger	# Rebuild vmd refs from the very cratch to not have duplicates in case we were called
4704f8177b5SMichal Berger	# multiple times.
4714f8177b5SMichal Berger	unset -v "${!_vmd_@}"
4724f8177b5SMichal Berger
4734f8177b5SMichal Berger	for bdf in "${!nvme_d[@]}"; do
4744f8177b5SMichal Berger		vmd=$(is_nvme_behind_vmd "$bdf") && _vmd=${vmd//[:.]/_} || continue
4754f8177b5SMichal Berger		nvme_vmd_d["$bdf"]=$vmd
4764f8177b5SMichal Berger		vmd_nvme_d["$vmd"]="_vmd_${_vmd}_nvmes[@]"
4774f8177b5SMichal Berger		((++vmd_nvme_count["$vmd"]))
4784f8177b5SMichal Berger		eval "_vmd_${_vmd}_nvmes+=($bdf)"
4794f8177b5SMichal Berger	done
4804f8177b5SMichal Berger}
4814f8177b5SMichal Berger
4824f8177b5SMichal Bergeris_nvme_behind_vmd() {
4834f8177b5SMichal Berger	local nvme_bdf=$1 dev_path
4844f8177b5SMichal Berger
4854f8177b5SMichal Berger	IFS="/" read -ra dev_path < <(readlink -f "/sys/bus/pci/devices/$nvme_bdf")
4864f8177b5SMichal Berger
4874f8177b5SMichal Berger	for dev in "${dev_path[@]}"; do
4884f8177b5SMichal Berger		[[ -n $dev && -n ${vmd_d["$dev"]} ]] && echo $dev && return 0
4894f8177b5SMichal Berger	done
4904f8177b5SMichal Berger	return 1
4914f8177b5SMichal Berger}
4924f8177b5SMichal Berger
4934f8177b5SMichal Bergeris_nvme_iommu_shared_with_vmd() {
4944f8177b5SMichal Berger	local nvme_bdf=$1 vmd
4954f8177b5SMichal Berger
4964f8177b5SMichal Berger	# This use-case is quite specific to vfio-pci|iommu setup
4974f8177b5SMichal Berger	is_iommu_enabled || return 1
4984f8177b5SMichal Berger
4994f8177b5SMichal Berger	[[ -n ${nvme_vmd_d["$nvme_bdf"]} ]] || return 1
5004f8177b5SMichal Berger	# nvme is behind VMD ...
5014f8177b5SMichal Berger	((pci_iommu_groups["$nvme_bdf"] == pci_iommu_groups["${nvme_vmd_d["$nvme_bdf"]}"])) || return 1
5024f8177b5SMichal Berger	# ... and it shares iommu_group with it
5034f8177b5SMichal Berger}
5044f8177b5SMichal Berger
505443e1ea3SJim Harriskmsg() {
506443e1ea3SJim Harris	((UID == 0)) || return 0
507443e1ea3SJim Harris	[[ -w /dev/kmsg && $(< /proc/sys/kernel/printk_devkmsg) == on ]] || return 0
508443e1ea3SJim Harris	echo "$*" > /dev/kmsg
509443e1ea3SJim Harris}
510443e1ea3SJim Harris
511*cb7af50cSMichal Bergerfunction get_block_dev_from_bdf() {
512*cb7af50cSMichal Berger	local bdf=$1
513*cb7af50cSMichal Berger	local block blocks=() ctrl sub
514*cb7af50cSMichal Berger
515*cb7af50cSMichal Berger	for block in /sys/block/!(nvme*); do
516*cb7af50cSMichal Berger		if [[ $(readlink -f "$block/device") == *"/$bdf/"* ]]; then
517*cb7af50cSMichal Berger			blocks+=("${block##*/}")
518*cb7af50cSMichal Berger		fi
519*cb7af50cSMichal Berger	done
520*cb7af50cSMichal Berger
521*cb7af50cSMichal Berger	blocks+=($(get_block_dev_from_nvme "$bdf"))
522*cb7af50cSMichal Berger
523*cb7af50cSMichal Berger	printf '%s\n' "${blocks[@]}"
524*cb7af50cSMichal Berger}
525*cb7af50cSMichal Berger
526*cb7af50cSMichal Bergerfunction get_block_dev_from_nvme() {
527*cb7af50cSMichal Berger	local bdf=$1 block ctrl sub
528*cb7af50cSMichal Berger
529*cb7af50cSMichal Berger	for ctrl in /sys/class/nvme/nvme*; do
530*cb7af50cSMichal Berger		[[ -e $ctrl/address && $(< "$ctrl/address") == "$bdf" ]] || continue
531*cb7af50cSMichal Berger		sub=$(< "$ctrl/subsysnqn") && break
532*cb7af50cSMichal Berger	done
533*cb7af50cSMichal Berger
534*cb7af50cSMichal Berger	[[ -n $sub ]] || return 0
535*cb7af50cSMichal Berger
536*cb7af50cSMichal Berger	for block in /sys/block/nvme*; do
537*cb7af50cSMichal Berger		[[ -e $block/hidden && $(< "$block/hidden") == 1 ]] && continue
538*cb7af50cSMichal Berger		if [[ -e $block/device/subsysnqn && $(< "$block/device/subsysnqn") == "$sub" ]]; then
539*cb7af50cSMichal Berger			echo "${block##*/}"
540*cb7af50cSMichal Berger		fi
541*cb7af50cSMichal Berger	done
542*cb7af50cSMichal Berger}
543*cb7af50cSMichal Berger
5445a21edf4SNick Connollyif [[ -e "$CONFIG_WPDK_DIR/bin/wpdk_common.sh" ]]; then
5455a21edf4SNick Connolly	# Adjust uname to report the operating system as WSL, Msys or Cygwin
5465a21edf4SNick Connolly	# and the kernel name as Windows. Define kill() to invoke the SIGTERM
5475a21edf4SNick Connolly	# handler before causing a hard stop with TerminateProcess.
5485a21edf4SNick Connolly	source "$CONFIG_WPDK_DIR/bin/wpdk_common.sh"
5495a21edf4SNick Connollyfi
5501e46e023SMaciej Mis
5511e46e023SMaciej Mis# Make sure we have access to proper binaries installed in pkgdep/common.sh
5521e46e023SMaciej Misif [[ -e /etc/opt/spdk-pkgdep/paths/export.sh ]]; then
5531e46e023SMaciej Mis	source /etc/opt/spdk-pkgdep/paths/export.sh
5541e46e023SMaciej Misfi > /dev/null
555