xref: /spdk/test/nvme/cuse/common.sh (revision b3bec07939ebe2ea2e0c43931705d32aa9e06719)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2023 Intel Corporation
4#  All rights reserved.
5#
6
7source "$rootdir/test/common/autotest_common.sh"
8
9shopt -s extglob
10
11NVME_CMD="/usr/local/src/nvme-cli/nvme"
12
13rpc_py=$rootdir/scripts/rpc.py
14
15declare -A ctrls=()
16declare -A nvmes=()
17declare -A bdfs=()
18nvme_name=""
19
20nvme_get() {
21	local ref=$1 reg val
22	shift
23
24	local -gA "$ref=()"
25	while IFS=":" read -r reg val; do
26		[[ -n $val ]] \
27			&& eval "${ref}[${reg//[[:space:]]/}]=\"${val##+([[:space:]])}\""
28	done < <($NVME_CMD "$@")
29}
30
31scan_nvme_ctrls() {
32	# Create set of references and bundle them together in global assoc arrays.
33	# Each controller's regs are mapped onto a separate array named as the target
34	# ctrl. Each ctrl also gets a dedicated array which holds references to each
35	# namespace device. E.g.:
36	#
37	#  ctrls["nvme0"]=nvme0
38	#    nvme0["mn"] nvme0["vid"]
39	#  nvmes["nvme0"]=nvme0_ns
40	#    nvme0_ns[1]=nvme0n1 nvme0_ns[2]=nvme0n2
41	#     nvme0n1["lbaf0"] nvme0n1["ncap"]
42	#  bdf["nvme0"]=0000:00:42.0
43	#
44	# Each of these can be accessed via get*() helpers defined below. E.g.:
45	# get_nvme_ctrl_feature nvme0 vid -> 0x8086
46	# get_nvme_ns_feature nvme0 1 ncap -> 0x2e9390b0
47	# get_nvme_nss nvme0 -> 1 2
48
49	local ctrl ctrl_dev reg val ns pci
50
51	for ctrl in /sys/class/nvme/nvme*; do
52		[[ -e $ctrl ]] || continue
53		pci=$(< "$ctrl/address")
54		pci_can_use "$pci" || continue
55		ctrl_dev=${ctrl##*/}
56		nvme_get "$ctrl_dev" id-ctrl "/dev/$ctrl_dev"
57		local -n _ctrl_ns=${ctrl_dev}_ns
58		for ns in "$ctrl/${ctrl##*/}n"*; do
59			[[ -e $ns ]] || continue
60			ns_dev=${ns##*/}
61			nvme_get "$ns_dev" id-ns "/dev/$ns_dev"
62			_ctrl_ns[${ns##*n}]=$ns_dev
63		done
64		ctrls["$ctrl_dev"]=$ctrl_dev
65		nvmes["$ctrl_dev"]=${ctrl_dev}_ns
66		bdfs["$ctrl_dev"]=$pci
67	done
68}
69
70get_nvme_ctrl_feature() {
71	local ctrl=$1 reg=${2:-cntlid}
72
73	[[ -n ${ctrls["$ctrl"]} ]] || return 1
74
75	local -n _ctrl=${ctrls["$ctrl"]}
76
77	[[ -n ${_ctrl["$reg"]} ]] || return 1
78	echo "${_ctrl["$reg"]}"
79}
80
81get_nvme_ns_feature() {
82	local ctrl=$1 ns=$2 reg=${3:-nsze}
83
84	[[ -n ${nvmes["$ctrl"]} ]] || return 1
85
86	local -n _nss=${nvmes["$ctrl"]}
87	[[ -n ${_nss[ns]} ]] || return 1
88
89	local -n _ns=${_nss[ns]}
90
91	[[ -n ${_ns["$reg"]} ]] || return 1
92	echo "${_ns["$reg"]}"
93}
94
95get_nvme_nss() {
96	local ctrl=$1
97
98	[[ -n ${nvmes["$ctrl"]} ]] || return 1
99	local -n _nss=${nvmes["$ctrl"]}
100
101	echo "${!_nss[@]}"
102}
103
104get_active_lbaf() {
105	local ctrl=$1 ns=$2 reg lbaf
106
107	[[ -n ${nvmes["$ctrl"]} ]] || return 1
108
109	local -n _nss=${nvmes["$ctrl"]}
110	[[ -n ${_nss[ns]} ]] || return 1
111
112	local -n _ns=${_nss[ns]}
113
114	for reg in "${!_ns[@]}"; do
115		[[ $reg == lbaf* ]] || continue
116		[[ ${_ns["$reg"]} == *"in use"* ]] || continue
117		echo "${reg/lbaf/}" && return 0
118	done
119	return 1
120}
121
122get_oacs() {
123	local ctrl=${1:-nvme0} bit=${2:-nsmgt}
124	local -A bits
125
126	# Figure 275: Identify – Identify Controller Data Structure, I/O Command Set Independent
127	bits["ss/sr"]=$((1 << 0))
128	bits["fnvme"]=$((1 << 1))
129	bits["fc/fi"]=$((1 << 2))
130	bits["nsmgt"]=$((1 << 3))
131	bits["self-test"]=$((1 << 4))
132	bits["directives"]=$((1 << 5))
133	bits["nvme-mi-s/r"]=$((1 << 6))
134	bits["virtmgt"]=$((1 << 7))
135	bits["doorbellbuf"]=$((1 << 8))
136	bits["getlba"]=$((1 << 9))
137	bits["commfeatlock"]=$((1 << 10))
138
139	bit=${bit,,}
140	[[ -n ${bits["$bit"]} ]] || return 1
141
142	(($(get_nvme_ctrl_feature "$ctrl" oacs) & bits["$bit"]))
143}
144
145get_nvmes_with_ns_management() {
146	((${#ctrls[@]} == 0)) && scan_nvme_ctrls
147
148	local ctrl
149	for ctrl in "${!ctrls[@]}"; do
150		get_oacs "$ctrl" nsmgt && echo "$ctrl"
151	done
152}
153
154get_nvme_with_ns_management() {
155	local _ctrls
156
157	_ctrls=($(get_nvmes_with_ns_management))
158	if ((${#_ctrls[@]} > 0)); then
159		echo "${_ctrls[0]}"
160		return 0
161	fi
162	return 1
163}
164
165get_ctratt() {
166	local ctrl=$1
167	get_nvme_ctrl_feature "$ctrl" ctratt
168}
169
170get_oncs() {
171	local ctrl=$1
172	get_nvme_ctrl_feature "$ctrl" oncs
173}
174
175ctrl_has_fdp() {
176	local ctrl=$1 ctratt
177
178	ctratt=$(get_ctratt "$ctrl")
179	# See include/spdk/nvme_spec.h
180	((ctratt & 1 << 19))
181}
182
183ctrl_has_scc() {
184	local ctrl=$1 oncs
185
186	oncs=$(get_oncs "$ctrl")
187	# See include/spdk/nvme_spec.h
188	((oncs & 1 << 8))
189}
190
191get_ctrls_with_feature() {
192	((${#ctrls[@]} == 0)) && scan_nvme_ctrls
193
194	local ctrl feature=${1:-fdp}
195
196	[[ $(type -t "ctrl_has_$feature") == function ]] || return 1
197
198	for ctrl in "${!ctrls[@]}"; do
199		"ctrl_has_$feature" "$ctrl" && echo "$ctrl"
200	done
201
202}
203
204get_ctrl_with_feature() {
205	local _ctrls feature=${1:-fdp}
206
207	_ctrls=($(get_ctrls_with_feature "$feature"))
208	if ((${#_ctrls[@]} > 0)); then
209		echo "${_ctrls[0]}"
210		return 0
211	fi
212	return 1
213}
214