1#!/usr/bin/ksh 2# 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11# 12 13# 14# Copyright 2024 Oxide Computer Company 15# 16 17# 18# This implements basic tests for nvmeadm(8). It expects to be passed a device 19# to operate on the same as the other non-destructive tests. It is important 20# that we only test non-destructive operations here. Even error paths for 21# destructive operations should be done elsewhere. 22# 23 24# 25# Set up the environment with a standard locale and debugging tools to help us 26# catch failures. 27# 28export LC_ALL=C.UTF-8 29export LD_PRELOAD=libumem.so 30export UMEM_DEBUG=default 31unalias -a 32set -o pipefail 33 34nt_prog=/usr/sbin/nvmeadm 35nt_arg0=$(basename $0) 36nt_exit=0 37nt_fail=0 38nt_dev="$NVME_TEST_DEVICE" 39nt_maj= 40nt_min= 41nt_ns= 42 43function warn 44{ 45 typeset msg="$*" 46 [[ -z "$msg" ]] && msg="failed" 47 echo "TEST FAILED: $msg" >&2 48 nt_exit=1 49 ((nt_fail++)) 50} 51 52function fatal 53{ 54 typeset msg="$*" 55 [[ -z "$msg" ]] && msg="failed" 56 echo "$nt_arg0: $msg" >&2 57 exit 1 58} 59 60# 61# Whether certain tests pass or fail depends on the version of the controller. 62# Capture that information now. 63# 64function capture_version 65{ 66 typeset vers 67 typeset nsmgmt 68 69 vers=$($nt_prog list -p -o version $nt_dev) 70 if (( $? != 0 )); then 71 fatal "failed to capture NVMe version from $nt_dev" 72 fi 73 74 IFS=. read -r nt_maj nt_min <<< "$vers" 75 76 if [[ -z "$nt_maj" ]]; then 77 fatal "failed to parse NVMe major version from $vers" 78 fi 79 80 if [[ -z "$nt_min" ]]; then 81 fatal "failed to parse NVMe minor version from $vers" 82 fi 83 84 printf "Testing device %s: NVMe Version %u.%u\n" "$nt_dev" "$nt_maj" \ 85 "$nt_min" 86 87 nsmgmt=$(nvmeadm identify $nt_dev | awk \ 88 '/Namespace Management:/{ print $3 }') 89 90 if (( $? != 0 )); then 91 fatal "failed to determine Namespace Management support from" \ 92 "$nt_dev" 93 fi 94 95 if [[ -n "$nsmgmt" && "$nsmgmt" == "supported" ]]; then 96 nt_ns="yes" 97 printf "%s has namespace management\n" "$nt_dev" 98 else 99 printf "%s does not support namespace management\n" "$nt_dev" 100 fi 101} 102 103# 104# Run some program whose output we don't care about. Only whether it exits 105# successfully or not. 106# 107function nvmeadm_fail 108{ 109 if "$nt_prog" $@ 2>/dev/null 1>/dev/null; then 110 warn "should have failed with args $@, but passed" 111 return; 112 fi 113 114 printf "TEST PASSED: program failed: %s\n" "$*" 115} 116 117# 118# Like the above, except we expect it to pass. 119# 120function nvmeadm_pass 121{ 122 if ! "$nt_prog" $@ 2>/dev/null 1>/dev/null; then 123 warn "should have passed with args $@, but failed" 124 return; 125 fi 126 127 printf "TEST PASSED: %s %s exited successfully\n" "$nt_prog" "$*" 128} 129 130# 131# This is a test that we expect to pass based upon the version of the controller. 132# 133function nvmeadm_pv 134{ 135 typeset vers="$1" 136 typeset maj min 137 shift 138 139 IFS=. read -r maj min <<< "$vers" 140 if [[ -z "$maj" ]]; then 141 fatal "failed to parse NVMe major version from test $vers" 142 fi 143 144 if [[ -z "$min" ]]; then 145 fatal "failed to parse NVMe minor version from test $vers" 146 fi 147 148 if (( nt_maj > maj || (nt_maj == maj && nt_min >= min) )); then 149 nvmeadm_pass $@ 150 else 151 nvmeadm_fail $@ 152 fi 153} 154 155# 156# Wrappers around nvmeadm_pv for the various versions we care about. 157# 158function nvmeadm_pv1v1 159{ 160 nvmeadm_pv "1.1" $@ 161} 162 163function nvmeadm_pv1v2 164{ 165 nvmeadm_pv "1.2" $@ 166} 167 168function nvmeadm_pv1v3 169{ 170 nvmeadm_pv "1.3" $@ 171} 172 173function nvmeadm_ns 174{ 175 if [[ "$nt_ns" == "yes" ]]; then 176 nvmeadm_pv "1.2" $@ 177 else 178 nvmeadm_fail $@ 179 fi 180} 181 182if [[ -n "$NVMEADM" ]]; then 183 nt_prog="$NVMEADM" 184fi 185 186# 187# Note, we assume that the wrappers have already validated that this disk exists 188# for us. This tells us that we can expect a basic and specific list to work. 189# 190if [[ -z "$nt_dev" ]]; then 191 fatal "missing disk definition for \$NVME_TEST_DEVICE" 192fi 193 194capture_version 195 196# 197# Explicitly give bad arguments where our bad arguments aren't related to the 198# device. 199# 200nvmeadm_fail 201nvmeadm_fail foobar 202nvmeadm_fail list nvme 203nvmeadm_fail list nvmecloud 204nvmeadm_fail list nvmeterra 205nvmeadm_fail list nvme00 206nvmeadm_fail list nvme01 207nvmeadm_fail list nvme0x0 208nvmeadm_fail list nvme000 209nvmeadm_fail list nvme001 210nvmeadm_fail list nvme/1 211nvmeadm_fail list $nt_dev foobar 212nvmeadm_fail list $nt_dev,foobar 213nvmeadm_fail list $nt_dev/ 214nvmeadm_fail list $nt_dev//1 215nvmeadm_fail list $nt_dev/terra 216nvmeadm_fail list $nt_dev/0 217nvmeadm_fail list $nt_dev/001 218nvmeadm_fail list $nt_dev/0x1 219nvmeadm_fail list $nt_dev/0o1 220nvmeadm_fail list $nt_dev/000 221nvmeadm_fail list $nt_dev/1asdf 222nvmeadm_fail list -p 223nvmeadm_fail list -o 224nvmeadm_fail list -o foobar 225nvmeadm_fail list -p -o foobar 226nvmeadm_fail list -p -o model,foobar 227nvmeadm_fail list -p -o model,foobar $nt_dev $nt_dev 228nvmeadm_fail list -p -o model,serial $nt_dev/1 $nt_dev 229nvmeadm_fail list -c $nt_dev foobar 230nvmeadm_fail list -c $nt_dev,foobar 231nvmeadm_fail list -c $nt_dev/ 232nvmeadm_fail list -c $nt_dev/terra 233nvmeadm_fail list -c -p 234nvmeadm_fail list -c -o 235nvmeadm_fail list -c -o foobar 236nvmeadm_fail list -c -p -o foobar 237nvmeadm_fail list -c -p -o model,foobar 238nvmeadm_fail list -c -p -o model,foobar $nt_dev $nt_dev 239nvmeadm_fail list -c -p -o model,serial $nt_dev/1 $nt_dev 240nvmeadm_fail identify 241nvmeadm_fail identify -t 242nvmeadm_fail identify -C 243nvmeadm_fail identify -c 244nvmeadm_fail identify -n 245nvmeadm_fail identify -n -a 246nvmeadm_fail identify -a 247nvmeadm_fail identify -d 248nvmeadm_fail identify -d $nt_dev 249nvmeadm_fail identify -d $nt_dev/edgar 250nvmeadm_fail identify -d $nt_dev/1,$nt_dev/sabin 251nvmeadm_fail identify -C -a $nt_dev 252nvmeadm_fail identify -C -n $nt_dev 253nvmeadm_fail identify -c -a $nt_dev 254nvmeadm_fail identify -c -n $nt_dev 255nvmeadm_fail identify $nt_dev $nt_dev 256nvmeadm_fail identify-controller $nt_dev/1 257nvmeadm_fail identify-controller $nt_dev $nt_dev 258nvmeadm_fail identify-controller -x 259nvmeadm_fail identify-controller -C 260nvmeadm_fail identify-controller -c 261nvmeadm_fail identify-controller -n 262nvmeadm_fail identify-controller -n -a 263nvmeadm_fail identify-controller -a 264nvmeadm_fail identify-controller -C -a $nt_dev 265nvmeadm_fail identify-controller -C -n $nt_dev 266nvmeadm_fail identify-controller -c -n $nt_dev 267nvmeadm_fail identify-controller -c -a $nt_dev 268nvmeadm_fail identify-controller -C $nt_dev/1 269nvmeadm_fail identify-controller -c $nt_dev/1 270nvmeadm_fail identify-controller -n $nt_dev/1 271nvmeadm_fail identify-controller -n -a $nt_dev/1 272nvmeadm_fail identify-namespace 273nvmeadm_fail identify-namespace $nt_dev 274nvmeadm_fail identify-namespace $nt_dev/1 $nt_dev/1 275nvmeadm_fail identify-namespace -C 276nvmeadm_fail identify-namespace -d 277nvmeadm_fail identify-namespace -c 278nvmeadm_fail identify-namespace -C $nt_dev 279nvmeadm_fail identify-namespace -d $nt_dev 280nvmeadm_fail identify-namespace -c $nt_dev 281 282# 283# Log page tests are constrained to NVMe 1.0 features to keep things simpler. 284# See discussion in the pass section. 285# 286nvmeadm_fail list-logpages 287nvmeadm_fail list-logpages -a 288nvmeadm_fail list-logpages -H 289nvmeadm_fail list-logpages -p 290nvmeadm_fail list-logpages -p $nt_dev 291nvmeadm_fail list-logpages -p -o locke $nt_dev 292nvmeadm_fail list-logpages -o shadow $nt_dev 293nvmeadm_fail list-logpages -o device,shadow $nt_dev 294nvmeadm_fail list-logpages -s kefka $nt_dev 295nvmeadm_fail list-logpages -s nvm,kefka $nt_dev 296nvmeadm_fail list-logpages $nt_dev kefka 297nvmeadm_fail list-logpages $nt_dev health umaro 298nvmeadm_fail list-logpages $nt_dev/1 error 299nvmeadm_fail list-logpages $nt_dev/mog 300nvmeadm_fail list-logpages -s ns $nt_dev/1 firmware 301nvmeadm_fail get-logpage 302nvmeadm_fail get-logpage health 303nvmeadm_fail get-logpage health health 304nvmeadm_fail get-logpage $nt_dev 305nvmeadm_fail get-logpage $nt_dev,$nt_dev/1 306nvmeadm_fail get-logpage $nt_dev $nt_dev 307nvmeadm_fail get-logpage $nt_dev sephiorth 308nvmeadm_fail get-logpage $nt_dev health sephiorth 309nvmeadm_fail get-logpage $nt_dev health,error 310nvmeadm_fail list-features 311nvmeadm_fail list-features -a 312nvmeadm_fail list-features -o csi 313nvmeadm_fail list-features -H 314nvmeadm_fail list-features -p 315nvmeadm_fail list-features -p $nt_dev 316nvmeadm_fail list-features -o magicite $nt_dev 317nvmeadm_fail list-features -o csi materia 318nvmeadm_fail list-features $nt_dev $nt_dev 319nvmeadm_fail list-features $nt_dev/1 $nt_dev/1 320nvmeadm_fail list-features $nt_dev/1 aerith 321nvmeadm_fail list-features $nt_dev aerith arb temp 322nvmeadm_fail get-features 323nvmeadm_fail get-features $nt_dev/cid 324nvmeadm_fail get-features vincent 325nvmeadm_fail get-features $nt_dev range 326nvmeadm_fail get-features $nt_dev/1 temp 327nvmeadm_fail get-features $nt_dev temp,tifa 328nvmeadm_fail get-features $nt_dev temp cloud 329 330nvmeadm_fail list-firmware 331nvmeadm_fail list-firmware -t 332nvmeadm_fail list-firmware $nt_dev/1 333nvmeadm_fail list-firmware $nt_dev/squall 334nvmeadm_fail list-firmware $nt_dev rinoa 335 336# 337# Tests that we expect to pass in some form. 338# 339nvmeadm_pass list 340nvmeadm_pass list $nt_dev 341nvmeadm_pass list $nt_dev/1 342nvmeadm_pass list $nt_dev,$nt_dev/1 343nvmeadm_pass list -p -o model,serial $nt_dev 344nvmeadm_pass list -p -o model,serial $nt_dev/1 345nvmeadm_pass list -p -o model,serial $nt_dev/1,$nt_dev 346nvmeadm_pass list -c 347nvmeadm_pass list -c $nt_dev 348nvmeadm_pass list -c $nt_dev/1 349nvmeadm_pass list -c $nt_dev,$nt_dev/1 350nvmeadm_pass list -c -p -o model,serial $nt_dev 351nvmeadm_pass list -c -p -o model,serial $nt_dev/1 352nvmeadm_pass list -c -p -o model,serial $nt_dev/1,$nt_dev 353nvmeadm_pass identify $nt_dev 354nvmeadm_pass identify $nt_dev/1 355nvmeadm_pass identify $nt_dev,$nt_dev/1 356nvmeadm_pass identify $nt_dev,$nt_dev 357nvmeadm_pass identify $nt_dev,$nt_dev/1,$nt_dev 358nvmeadm_ns identify -C $nt_dev 359nvmeadm_ns identify -c $nt_dev 360nvmeadm_pv1v3 identify -d $nt_dev/1 361nvmeadm_pv1v1 identify -n $nt_dev 362nvmeadm_ns identify -n -a $nt_dev 363nvmeadm_ns identify-controller -C $nt_dev 364nvmeadm_ns identify-controller -c $nt_dev 365nvmeadm_pv1v1 identify-controller -n $nt_dev 366nvmeadm_ns identify-controller -n -a $nt_dev 367 368# 369# All of our list- and get-logpage tests strictly use the 3 NVMe 1.0 log pages: 370# error, health, firmware. Note: NVMe 1.0 did not define any namespace-specific 371# log pages, the health log page was changed later. Therefore there are no tests 372# specific to solely namespace scope right now. 373# 374nvmeadm_pass list-logpages $nt_dev 375nvmeadm_pass list-logpages -H $nt_dev 376nvmeadm_pass list-logpages -o device $nt_dev 377nvmeadm_pass list-logpages -H -o device $nt_dev 378nvmeadm_pass list-logpages -o \ 379 device,name,desc,scope,fields,csi,lid,impl,size,minsize,sources,kind $nt_dev 380nvmeadm_pass list-logpages -p -o lid $nt_dev 381nvmeadm_pass list-logpages -H -p -o lid $nt_dev 382nvmeadm_pass list-logpages -s controller $nt_dev 383nvmeadm_pass list-logpages -s controller -H $nt_dev 384nvmeadm_pass list-logpages -s controller -H -o device $nt_dev 385nvmeadm_pass list-logpages -s controller -o \ 386 device,name,desc,scope,fields,csi,lid,impl,size,minsize,sources,kind $nt_dev 387nvmeadm_pass list-logpages -s controller -p -o lid $nt_dev 388nvmeadm_pass list-logpages -s controller,nvm $nt_dev 389nvmeadm_pass list-logpages -s controller,nvm,ns $nt_dev 390nvmeadm_pass list-logpages $nt_dev,$nt_dev 391nvmeadm_pass list-logpages $nt_dev error 392nvmeadm_pass list-logpages $nt_dev health 393nvmeadm_pass list-logpages -a $nt_dev 394nvmeadm_pass list-logpages -a $nt_dev health 395nvmeadm_pass list-logpages -s controller $nt_dev health 396nvmeadm_pass get-logpage $nt_dev health 397nvmeadm_pass get-logpage $nt_dev firmware 398nvmeadm_pass get-logpage $nt_dev,$nt_dev firmware 399nvmeadm_pass list-features $nt_dev 400nvmeadm_pass list-features -H $nt_dev 401nvmeadm_pass list-features -o device $nt_dev 402nvmeadm_pass list-features -p -o device,impl $nt_dev 403nvmeadm_pass list-features -o \ 404 device,short,spec,fid,scope,kind,csi,flags,get-in,get-out,set-out,datalen \ 405 $nt_dev 406nvmeadm_pass list-features -a $nt_dev 407nvmeadm_pass list-features $nt_dev/1 408nvmeadm_pass list-features -H $nt_dev/1 409nvmeadm_pass list-features -o short,fid $nt_dev/1 410nvmeadm_pass list-features -p -o device,impl $nt_dev/1 411nvmeadm_pass list-features -o \ 412 device,short,spec,fid,scope,kind,csi,flags,get-in,get-out,set-out,datalen \ 413 $nt_dev/1 414nvmeadm_pass list-features -a $nt_dev/1 415nvmeadm_pass list-features $nt_dev,$nt_dev/1 416nvmeadm_pass list-features $nt_dev,$nt_dev/1,$nt_dev 417nvmeadm_pass list-features $nt_dev pm 418nvmeadm_pass list-features $nt_dev arbitration 419nvmeadm_pass list-features $nt_dev Arbitration 420nvmeadm_pass list-features $nt_dev pm Arbitration temp 421# 422# If you find a get-features without arguments is causing issues, please feel 423# free to remove this test. 424# 425nvmeadm_pass get-features $nt_dev 426nvmeadm_pass get-features $nt_dev temp 427nvmeadm_pass get-features $nt_dev temp,vector 428nvmeadm_pass get-features $nt_dev,$nt_dev arb 429 430nvmeadm_pass list-firmware $nt_dev 431 432# 433# Here we come back and use bad controller names that should not work. 434# These specifically do not rely on $nt_dev. 435# 436 437if (( nt_exit == 0 )); then 438 printf "All tests passed successfully!\n" 439else 440 printf "%u tests failed!\n" "$nt_fail" 441fi 442 443exit $nt_exit 444