xref: /spdk/scripts/common/setup/interactive.sh (revision 0070858e33ec0937e93e68b06a7f170b02a352b6)
17a1bd398SMichal Berger#!/usr/bin/env bash
27a1bd398SMichal Berger#  SPDX-License-Identifier: BSD-3-Clause
37a1bd398SMichal Berger#  Copyright (C) 2023 Intel Corporation
47a1bd398SMichal Berger#  All rights reserved.
57a1bd398SMichal Berger#
67a1bd398SMichal Bergerset +e
77a1bd398SMichal Berger
87a1bd398SMichal Bergeryn() {
97a1bd398SMichal Berger	local -A yn=()
107a1bd398SMichal Berger	local _yn
117a1bd398SMichal Berger
127a1bd398SMichal Berger	yn["y"]=0 yn["n"]=1
137a1bd398SMichal Berger
147a1bd398SMichal Berger	while read -rp "$* (y|N)> " _yn || true; do
157a1bd398SMichal Berger		_yn=${_yn::1} _yn=${_yn,,} _yn=${_yn:-n}
167a1bd398SMichal Berger		[[ -n ${yn["$_yn"]} ]] && return "${yn["$_yn"]}"
177a1bd398SMichal Berger	done
187a1bd398SMichal Berger}
197a1bd398SMichal Berger
207a1bd398SMichal Bergerelevate() {
217a1bd398SMichal Berger	((UID != 0)) || return 0
227a1bd398SMichal Berger
237a1bd398SMichal Berger	if yn "You ($UID) need to be root to commit any changes. Elevate privileges?"; then
2444fef7d2SMichal Berger		exec sudo -E "$rootdir/scripts/setup.sh" interactive "$@"
257a1bd398SMichal Berger	fi
267a1bd398SMichal Berger}
277a1bd398SMichal Berger
287a1bd398SMichal Bergerstdin() {
297a1bd398SMichal Berger	[[ ! -t 0 ]] || return 0
307a1bd398SMichal Berger
317a1bd398SMichal Berger	echo "Requested interactive mode but stdin is not attached to a terminal, bailing" >&2
327a1bd398SMichal Berger	return 1
337a1bd398SMichal Berger}
347a1bd398SMichal Berger
357a1bd398SMichal Bergermain_menu() {
3644fef7d2SMichal Berger	local type=all answer quick_mode=$1
377a1bd398SMichal Berger
387a1bd398SMichal Berger	stdin || return 1
3944fef7d2SMichal Berger	elevate "$quick_mode"
4044fef7d2SMichal Berger
4144fef7d2SMichal Berger	case "${quick_mode,,}" in
4244fef7d2SMichal Berger		config | reset)
4344fef7d2SMichal Berger			editor odevices quick && mode=$quick_mode
4444fef7d2SMichal Berger			return
4544fef7d2SMichal Berger			;;
4644fef7d2SMichal Berger	esac
477a1bd398SMichal Berger
487a1bd398SMichal Berger	while ((1)); do
497a1bd398SMichal Berger		cat <<- MENU
507a1bd398SMichal Berger
517a1bd398SMichal Berger			1) List PCI Devices [Currently Listing: "$type"]
527a1bd398SMichal Berger			2) Change Devices To List
537a1bd398SMichal Berger			3) Mark Device As Blocked (${PCI_BLOCKED:-none})
547a1bd398SMichal Berger			4) Mark Device As Allowed (${PCI_ALLOWED:-none})
557a1bd398SMichal Berger			5) Override Device In-Use Status
567a1bd398SMichal Berger			$([[ $os == Linux ]] && echo "6) Bind Device")
577a1bd398SMichal Berger
587a1bd398SMichal Berger			c) configure
597a1bd398SMichal Berger			s) status
607a1bd398SMichal Berger			r) reset
617a1bd398SMichal Berger			$([[ $os == Linux ]] && echo "hp) hugepages")
627a1bd398SMichal Berger
637a1bd398SMichal Berger			Q) Quit
647a1bd398SMichal Berger			U) Update Devices View
657a1bd398SMichal Berger
667a1bd398SMichal Berger		MENU
677a1bd398SMichal Berger
687a1bd398SMichal Berger		read -rp "> " answer || answer=q
697a1bd398SMichal Berger
707a1bd398SMichal Berger		case "${answer,,}" in
717a1bd398SMichal Berger			1) pdevices ;;
727a1bd398SMichal Berger			2) ctype && pdevices ;;
737a1bd398SMichal Berger			3) fdevices 0 ;;
747a1bd398SMichal Berger			4) fdevices 1 ;;
757a1bd398SMichal Berger			5) odevices ;;
76daf647bcSMichal Berger			5e) editor odevices ;;
77c97b31f8SMichal Berger			6) bdevices ;;&
787a1bd398SMichal Berger			q) yn "Are you sure you want to quit?" && return 1 ;;
797a1bd398SMichal Berger			c | commit | config)
807a1bd398SMichal Berger				yn "Are you sure you want jump to config mode?" || continue
817a1bd398SMichal Berger				mode=config
827a1bd398SMichal Berger				return
837a1bd398SMichal Berger				;;
84c97b31f8SMichal Berger			hp) hugepages ;;
857a1bd398SMichal Berger			s | status) status ;;
867a1bd398SMichal Berger			r | reset)
877a1bd398SMichal Berger				yn "Are you sure you want jump to reset mode?" || continue
887a1bd398SMichal Berger				mode=reset
897a1bd398SMichal Berger				return
907a1bd398SMichal Berger				;;
91c97b31f8SMichal Berger			6 | u | update) update_status ;;
927a1bd398SMichal Berger		esac
937a1bd398SMichal Berger	done
947a1bd398SMichal Berger}
957a1bd398SMichal Berger
967a1bd398SMichal Bergergdevices() {
977a1bd398SMichal Berger	if [[ $type == all ]]; then
987a1bd398SMichal Berger		local -gn dev_ref=all_devices_d
997a1bd398SMichal Berger	else
1007a1bd398SMichal Berger		local -gn dev_ref=${type}_d
1017a1bd398SMichal Berger	fi
1027a1bd398SMichal Berger}
1037a1bd398SMichal Berger
1047a1bd398SMichal Bergerpdevices() {
1057a1bd398SMichal Berger	gdevices
1067a1bd398SMichal Berger
107daf647bcSMichal Berger	local set_marker=$1
1087a1bd398SMichal Berger	local use_map=()
109daf647bcSMichal Berger	local -A markers=()
110daf647bcSMichal Berger
1117a1bd398SMichal Berger	use_map[0]="not used" use_map[1]="used"
112daf647bcSMichal Berger	markers["not used"]=pick markers["used"]=skip
1137a1bd398SMichal Berger
1147a1bd398SMichal Berger	if ((${#dev_ref[@]} == 0)); then
1157a1bd398SMichal Berger		echo "No devices found"
1167a1bd398SMichal Berger	else
1177a1bd398SMichal Berger		for dev in "${!dev_ref[@]}"; do
1184f8177b5SMichal Berger			printf '%s- %s [%s, %s] (%s@%s:%s)%s\n' \
119daf647bcSMichal Berger				"${set_marker:+${markers["${use_map[all_devices_d["$dev"]]}"]} }" \
1204f8177b5SMichal Berger				"$dev" "${use_map[all_devices_d["$dev"]]}" "${pci_bus_driver["$dev"]:-none}" \
121f1068fefSMichal Berger				"${all_devices_type_d["$dev"]}" \
122f1068fefSMichal Berger				"${pci_ids_vendor["$dev"]}" \
1234f8177b5SMichal Berger				"${pci_ids_device["$dev"]}" \
1244f8177b5SMichal Berger				"${nvme_vmd_d["$dev"]:+"@(VMD -> ${nvme_vmd_d["$dev"]})"}"
1257a1bd398SMichal Berger		done
1267a1bd398SMichal Berger	fi
1277a1bd398SMichal Berger}
1287a1bd398SMichal Berger
1297a1bd398SMichal Bergerctype() {
1307a1bd398SMichal Berger	local type_to_set
1317a1bd398SMichal Berger	local -n types_ref=types_d
1327a1bd398SMichal Berger
1337a1bd398SMichal Berger	while read -rp "(${!types_ref[*]} all)> " type_to_set; do
1347a1bd398SMichal Berger		type_to_set=${type_to_set,,}
1357a1bd398SMichal Berger		if [[ -z $type_to_set ]]; then
1367a1bd398SMichal Berger			return
1377a1bd398SMichal Berger		elif [[ -n ${types_ref["$type_to_set"]} || $type_to_set == all ]]; then
1387a1bd398SMichal Berger			type=$type_to_set
1397a1bd398SMichal Berger			return
1407a1bd398SMichal Berger		fi
1417a1bd398SMichal Berger	done
1427a1bd398SMichal Berger}
1437a1bd398SMichal Berger
1447a1bd398SMichal Bergerfdevices() {
1457a1bd398SMichal Berger	local action=${1:-0} bdf
1467a1bd398SMichal Berger	local am=()
1477a1bd398SMichal Berger	local -gA action_0 action_1
1487a1bd398SMichal Berger
1497a1bd398SMichal Berger	am[0]=PCI_BLOCKED am[1]=PCI_ALLOWED
1507a1bd398SMichal Berger
1517a1bd398SMichal Berger	gdevices
1527a1bd398SMichal Berger	local -n action_ref=action_${action}
1537a1bd398SMichal Berger	local -n action_ref_rev=action_$((!action))
1547a1bd398SMichal Berger
1557a1bd398SMichal Berger	while read -rp "(${!am[action]:-BDF})> " bdf; do
1567a1bd398SMichal Berger		bdf=${bdf,,}
1577a1bd398SMichal Berger		if [[ -z $bdf ]]; then
1587a1bd398SMichal Berger			return
1597a1bd398SMichal Berger		elif [[ -n ${dev_ref["$bdf"]} ]]; then
1607a1bd398SMichal Berger			if [[ -n ${action_ref["$bdf"]} ]]; then
1617a1bd398SMichal Berger				unset -v "action_ref[$bdf]"
1627a1bd398SMichal Berger			else
1637a1bd398SMichal Berger				action_ref["$bdf"]=1
1647a1bd398SMichal Berger				unset -v "action_ref_rev[$bdf]"
1657a1bd398SMichal Berger			fi
1667a1bd398SMichal Berger			eval "${am[action]}='${!action_ref[*]}'"
1677a1bd398SMichal Berger			eval "${am[!action]}='${!action_ref_rev[*]}'"
1687a1bd398SMichal Berger		elif [[ -z ${dev_ref["$bdf"]} ]]; then
1697a1bd398SMichal Berger			unset -v "action_ref[$bdf]"
1707a1bd398SMichal Berger			eval "${am[action]}='${!action_ref[*]}'"
1717a1bd398SMichal Berger		fi
1727a1bd398SMichal Berger	done
1737a1bd398SMichal Berger}
1747a1bd398SMichal Berger
175daf647bcSMichal Bergereditor() {
17644fef7d2SMichal Berger	local devs_list=() devs_picked=() devs_skipped=()
177daf647bcSMichal Berger	local editor=${VISUAL:-${EDITOR:-vim}}
178daf647bcSMichal Berger	local tmp_file
179daf647bcSMichal Berger
180daf647bcSMichal Berger	type -P "$editor" > /dev/null || return
181daf647bcSMichal Berger
182daf647bcSMichal Berger	mapfile -t devs_list < <(pdevices markers)
183daf647bcSMichal Berger
184daf647bcSMichal Berger	tmp_file=$(mktemp -u)
185daf647bcSMichal Berger	cat <<- ODEVICES > "$tmp_file" || return
186daf647bcSMichal Berger		# Listing '$type' devices
187daf647bcSMichal Berger		#   Devices marked as "used" (i.e. contains any data) will be skipped by default
188daf647bcSMichal Berger		#   Devices marked as "not used" (i.e. does not contain data) will be picked by default
189daf647bcSMichal Berger
190daf647bcSMichal Berger		$(printf '%s\n' "${devs_list[@]}")
191daf647bcSMichal Berger
192daf647bcSMichal Berger		# p, pick devices
193daf647bcSMichal Berger		# s, skip devices
194daf647bcSMichal Berger
195daf647bcSMichal Berger		$([[ $editor == vi?(m) ]] && echo "# :cq[!] to not save any changes")
196daf647bcSMichal Berger	ODEVICES
197daf647bcSMichal Berger
198daf647bcSMichal Berger	"$editor" "$tmp_file" || return
199daf647bcSMichal Berger	[[ -s $tmp_file ]] || return
200daf647bcSMichal Berger
201daf647bcSMichal Berger	local action dev _type
202daf647bcSMichal Berger	while read -r action _ dev _type; do
203daf647bcSMichal Berger		case "${action,,}" in
204daf647bcSMichal Berger			s | skip)
205daf647bcSMichal Berger				[[ $_type != *"not used"* ]] && continue
20644fef7d2SMichal Berger				devs_skipped+=("$dev")
207daf647bcSMichal Berger				;;
208daf647bcSMichal Berger			p | pick)
209daf647bcSMichal Berger				[[ $_type == *"not used"* ]] && continue
21044fef7d2SMichal Berger				devs_picked+=("$dev")
211daf647bcSMichal Berger				;;
212daf647bcSMichal Berger		esac
213daf647bcSMichal Berger	done < "$tmp_file"
214daf647bcSMichal Berger	rm "$tmp_file"
215daf647bcSMichal Berger
21644fef7d2SMichal Berger	if [[ $2 == quick ]] && ((${#devs_picked[@]} > 0)); then
21744fef7d2SMichal Berger		if ! yn "Detected data on some of the devices (${devs_picked[*]}). Continue?"; then
21844fef7d2SMichal Berger			return 1
21944fef7d2SMichal Berger		fi
22044fef7d2SMichal Berger	fi
22144fef7d2SMichal Berger
22244fef7d2SMichal Berger	"$1" < <(printf '%s\n' "${devs_skipped[@]}" "${devs_picked[@]}")
223daf647bcSMichal Berger
224daf647bcSMichal Berger}
225daf647bcSMichal Berger
2267a1bd398SMichal Bergerodevices() {
2277a1bd398SMichal Berger	local bdf
2287a1bd398SMichal Berger
2297a1bd398SMichal Berger	type=all gdevices
2307a1bd398SMichal Berger
2317a1bd398SMichal Berger	while read -rp "(BDF)> " bdf; do
2327a1bd398SMichal Berger		bdf=${bdf,,}
2337a1bd398SMichal Berger		if [[ -z $bdf ]]; then
2347a1bd398SMichal Berger			return
2357a1bd398SMichal Berger		elif [[ -n ${dev_ref["$bdf"]} ]]; then
2367a1bd398SMichal Berger			dev_ref["$bdf"]=$((!dev_ref["$bdf"]))
2377a1bd398SMichal Berger		fi
2387a1bd398SMichal Berger	done
2397a1bd398SMichal Berger}
2407a1bd398SMichal Berger
2417a1bd398SMichal Bergerbdevices() {
2427a1bd398SMichal Berger	[[ $os == Linux ]] || return 0
2437a1bd398SMichal Berger
244*2e497261SMichal Berger	local bdf driver
2457a1bd398SMichal Berger
2467a1bd398SMichal Berger	gdevices
2477a1bd398SMichal Berger
248*2e497261SMichal Berger	while read -rp "(BDF)> " bdf; do
249*2e497261SMichal Berger		bdf=${bdf,,}
250*2e497261SMichal Berger		if [[ -z $bdf ]]; then
2517a1bd398SMichal Berger			return
2527a1bd398SMichal Berger		fi
2537a1bd398SMichal Berger
254*2e497261SMichal Berger		[[ -n ${dev_ref["$bdf"]} ]] || continue
2557a1bd398SMichal Berger
256*2e497261SMichal Berger		pdriver "$bdf"
257*2e497261SMichal Berger
258*2e497261SMichal Berger		while read -rp "Select driver ($bdf)> " driver; do
259*2e497261SMichal Berger			driver=${driver,,}
260*2e497261SMichal Berger			if [[ -z $driver ]]; then
261*2e497261SMichal Berger				continue 2
262*2e497261SMichal Berger			fi
263*2e497261SMichal Berger			if [[ $driver == "${pci_bus_driver["$bdf"]}" ]]; then
2647a1bd398SMichal Berger				echo "$bdf already bound to $driver"
2657a1bd398SMichal Berger				continue
2667a1bd398SMichal Berger			fi
267*2e497261SMichal Berger			break
268*2e497261SMichal Berger		done
2697a1bd398SMichal Berger
270*2e497261SMichal Berger		# Try to be nice and silently attempt to load the driver just in case
271*2e497261SMichal Berger		modprobe -q "$driver" || true
272*2e497261SMichal Berger
273*2e497261SMichal Berger		if yn "$bdf currently bound to ${pci_bus_driver["$bdf"]:-none}. Bind to $driver?"; then
2747a1bd398SMichal Berger			linux_bind_driver "$bdf" "$driver"
275*2e497261SMichal Berger			return
2767a1bd398SMichal Berger		fi
2777a1bd398SMichal Berger	done
2787a1bd398SMichal Berger}
2797a1bd398SMichal Berger
280*2e497261SMichal Bergerpdriver() {
281*2e497261SMichal Berger	local bdf=$1
282*2e497261SMichal Berger
283*2e497261SMichal Berger	cat <<- DRIVER
284*2e497261SMichal Berger
285*2e497261SMichal Berger		$bdf:
286*2e497261SMichal Berger		  main driver: $(collect_driver "$bdf")
287*2e497261SMichal Berger		  current driver: ${pci_bus_driver["$bdf"]:-none}
288*2e497261SMichal Berger
289*2e497261SMichal Berger	DRIVER
290*2e497261SMichal Berger}
291*2e497261SMichal Berger
2927a1bd398SMichal Bergerstatus() {
2937a1bd398SMichal Berger	local _os=${os,,}
2947a1bd398SMichal Berger
2957a1bd398SMichal Berger	if [[ $(type -t "status_${_os}") == function ]]; then
2967a1bd398SMichal Berger		"status_${_os}"
297f01d428bSMichal Berger	fi 2> /dev/null
2987a1bd398SMichal Berger}
2997a1bd398SMichal Berger
3007a1bd398SMichal Bergerhugepages() {
3017a1bd398SMichal Berger	[[ $os == Linux ]] || return 0
3027a1bd398SMichal Berger	local hp
3037a1bd398SMichal Berger
3047a1bd398SMichal Berger	while read -rp "('clear' 'even' 'commit' HUGEMEM[=$HUGEMEM MB])> " hp; do
3057a1bd398SMichal Berger		hp=${hp,,}
3067a1bd398SMichal Berger		if [[ -z $hp ]]; then
3077a1bd398SMichal Berger			return
3087a1bd398SMichal Berger		elif [[ $hp == clear ]]; then
3097a1bd398SMichal Berger			clear_hugepages
3107a1bd398SMichal Berger			return
3117a1bd398SMichal Berger		elif [[ $hp =~ ^[1-9][0-9]*$ ]]; then
3127a1bd398SMichal Berger			NRHUGE=""
3137a1bd398SMichal Berger			HUGEMEM=$hp
3147a1bd398SMichal Berger		elif [[ $hp == commit ]]; then
3157a1bd398SMichal Berger			set_hp
3167a1bd398SMichal Berger			configure_linux_hugepages
3177a1bd398SMichal Berger			return
3187a1bd398SMichal Berger		fi
3197a1bd398SMichal Berger	done
3207a1bd398SMichal Berger}
321c97b31f8SMichal Berger
322c97b31f8SMichal Bergerupdate_status() {
323c97b31f8SMichal Berger	CMD=reset cache_pci_bus
324c97b31f8SMichal Berger	collect_devices
325c97b31f8SMichal Berger}
326