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