#!/usr/bin/ksh # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2024 Oxide Computer Company # # # This implements basic tests for nvmeadm(8). It expects to be passed a device # to operate on the same as the other non-destructive tests. It is important # that we only test non-destructive operations here. Even error paths for # destructive operations should be done elsewhere. # # # Set up the environment with a standard locale and debugging tools to help us # catch failures. # export LC_ALL=C.UTF-8 export LD_PRELOAD=libumem.so export UMEM_DEBUG=default unalias -a set -o pipefail nt_prog=/usr/sbin/nvmeadm nt_arg0=$(basename $0) nt_exit=0 nt_fail=0 nt_dev="$NVME_TEST_DEVICE" nt_maj= nt_min= nt_ns= function warn { typeset msg="$*" [[ -z "$msg" ]] && msg="failed" echo "TEST FAILED: $msg" >&2 nt_exit=1 ((nt_fail++)) } function fatal { typeset msg="$*" [[ -z "$msg" ]] && msg="failed" echo "$nt_arg0: $msg" >&2 exit 1 } # # Whether certain tests pass or fail depends on the version of the controller. # Capture that information now. # function capture_version { typeset vers typeset nsmgmt vers=$($nt_prog list -p -o version $nt_dev) if (( $? != 0 )); then fatal "failed to capture NVMe version from $nt_dev" fi IFS=. read -r nt_maj nt_min <<< "$vers" if [[ -z "$nt_maj" ]]; then fatal "failed to parse NVMe major version from $vers" fi if [[ -z "$nt_min" ]]; then fatal "failed to parse NVMe minor version from $vers" fi printf "Testing device %s: NVMe Version %u.%u\n" "$nt_dev" "$nt_maj" \ "$nt_min" nsmgmt=$(nvmeadm identify $nt_dev | awk \ '/Namespace Management:/{ print $3 }') if (( $? != 0 )); then fatal "failed to determine Namespace Management support from" \ "$nt_dev" fi if [[ -n "$nsmgmt" && "$nsmgmt" == "supported" ]]; then nt_ns="yes" printf "%s has namespace management\n" "$nt_dev" else printf "%s does not support namespace management\n" "$nt_dev" fi } # # Run some program whose output we don't care about. Only whether it exits # successfully or not. # function nvmeadm_fail { if "$nt_prog" $@ 2>/dev/null 1>/dev/null; then warn "should have failed with args $@, but passed" return; fi printf "TEST PASSED: program failed: %s\n" "$*" } # # Like the above, except we expect it to pass. # function nvmeadm_pass { if ! "$nt_prog" $@ 2>/dev/null 1>/dev/null; then warn "should have passed with args $@, but failed" return; fi printf "TEST PASSED: %s %s exited successfully\n" "$nt_prog" "$*" } # # This is a test that we expect to pass based upon the version of the controller. # function nvmeadm_pv { typeset vers="$1" typeset maj min shift IFS=. read -r maj min <<< "$vers" if [[ -z "$maj" ]]; then fatal "failed to parse NVMe major version from test $vers" fi if [[ -z "$min" ]]; then fatal "failed to parse NVMe minor version from test $vers" fi if (( nt_maj > maj || (nt_maj == maj && nt_min >= min) )); then nvmeadm_pass $@ else nvmeadm_fail $@ fi } # # Wrappers around nvmeadm_pv for the various versions we care about. # function nvmeadm_pv1v1 { nvmeadm_pv "1.1" $@ } function nvmeadm_pv1v2 { nvmeadm_pv "1.2" $@ } function nvmeadm_pv1v3 { nvmeadm_pv "1.3" $@ } function nvmeadm_ns { if [[ "$nt_ns" == "yes" ]]; then nvmeadm_pv "1.2" $@ else nvmeadm_fail $@ fi } if [[ -n "$NVMEADM" ]]; then nt_prog="$NVMEADM" fi # # Note, we assume that the wrappers have already validated that this disk exists # for us. This tells us that we can expect a basic and specific list to work. # if [[ -z "$nt_dev" ]]; then fatal "missing disk definition for \$NVME_TEST_DEVICE" fi capture_version # # Explicitly give bad arguments where our bad arguments aren't related to the # device. # nvmeadm_fail nvmeadm_fail foobar nvmeadm_fail list nvme nvmeadm_fail list nvmecloud nvmeadm_fail list nvmeterra nvmeadm_fail list nvme00 nvmeadm_fail list nvme01 nvmeadm_fail list nvme0x0 nvmeadm_fail list nvme000 nvmeadm_fail list nvme001 nvmeadm_fail list nvme/1 nvmeadm_fail list $nt_dev foobar nvmeadm_fail list $nt_dev,foobar nvmeadm_fail list $nt_dev/ nvmeadm_fail list $nt_dev//1 nvmeadm_fail list $nt_dev/terra nvmeadm_fail list $nt_dev/0 nvmeadm_fail list $nt_dev/001 nvmeadm_fail list $nt_dev/0x1 nvmeadm_fail list $nt_dev/0o1 nvmeadm_fail list $nt_dev/000 nvmeadm_fail list $nt_dev/1asdf nvmeadm_fail list -p nvmeadm_fail list -o nvmeadm_fail list -o foobar nvmeadm_fail list -p -o foobar nvmeadm_fail list -p -o model,foobar nvmeadm_fail list -p -o model,foobar $nt_dev $nt_dev nvmeadm_fail list -p -o model,serial $nt_dev/1 $nt_dev nvmeadm_fail list -c $nt_dev foobar nvmeadm_fail list -c $nt_dev,foobar nvmeadm_fail list -c $nt_dev/ nvmeadm_fail list -c $nt_dev/terra nvmeadm_fail list -c -p nvmeadm_fail list -c -o nvmeadm_fail list -c -o foobar nvmeadm_fail list -c -p -o foobar nvmeadm_fail list -c -p -o model,foobar nvmeadm_fail list -c -p -o model,foobar $nt_dev $nt_dev nvmeadm_fail list -c -p -o model,serial $nt_dev/1 $nt_dev nvmeadm_fail identify nvmeadm_fail identify -t nvmeadm_fail identify -C nvmeadm_fail identify -c nvmeadm_fail identify -n nvmeadm_fail identify -n -a nvmeadm_fail identify -a nvmeadm_fail identify -d nvmeadm_fail identify -d $nt_dev nvmeadm_fail identify -d $nt_dev/edgar nvmeadm_fail identify -d $nt_dev/1,$nt_dev/sabin nvmeadm_fail identify -C -a $nt_dev nvmeadm_fail identify -C -n $nt_dev nvmeadm_fail identify -c -a $nt_dev nvmeadm_fail identify -c -n $nt_dev nvmeadm_fail identify $nt_dev $nt_dev nvmeadm_fail identify-controller $nt_dev/1 nvmeadm_fail identify-controller $nt_dev $nt_dev nvmeadm_fail identify-controller -x nvmeadm_fail identify-controller -C nvmeadm_fail identify-controller -c nvmeadm_fail identify-controller -n nvmeadm_fail identify-controller -n -a nvmeadm_fail identify-controller -a nvmeadm_fail identify-controller -C -a $nt_dev nvmeadm_fail identify-controller -C -n $nt_dev nvmeadm_fail identify-controller -c -n $nt_dev nvmeadm_fail identify-controller -c -a $nt_dev nvmeadm_fail identify-controller -C $nt_dev/1 nvmeadm_fail identify-controller -c $nt_dev/1 nvmeadm_fail identify-controller -n $nt_dev/1 nvmeadm_fail identify-controller -n -a $nt_dev/1 nvmeadm_fail identify-namespace nvmeadm_fail identify-namespace $nt_dev nvmeadm_fail identify-namespace $nt_dev/1 $nt_dev/1 nvmeadm_fail identify-namespace -C nvmeadm_fail identify-namespace -d nvmeadm_fail identify-namespace -c nvmeadm_fail identify-namespace -C $nt_dev nvmeadm_fail identify-namespace -d $nt_dev nvmeadm_fail identify-namespace -c $nt_dev # # Log page tests are constrained to NVMe 1.0 features to keep things simpler. # See discussion in the pass section. # nvmeadm_fail list-logpages nvmeadm_fail list-logpages -a nvmeadm_fail list-logpages -H nvmeadm_fail list-logpages -p nvmeadm_fail list-logpages -p $nt_dev nvmeadm_fail list-logpages -p -o locke $nt_dev nvmeadm_fail list-logpages -o shadow $nt_dev nvmeadm_fail list-logpages -o device,shadow $nt_dev nvmeadm_fail list-logpages -s kefka $nt_dev nvmeadm_fail list-logpages -s nvm,kefka $nt_dev nvmeadm_fail list-logpages $nt_dev kefka nvmeadm_fail list-logpages $nt_dev health umaro nvmeadm_fail list-logpages $nt_dev/1 error nvmeadm_fail list-logpages $nt_dev/mog nvmeadm_fail list-logpages -s ns $nt_dev/1 firmware nvmeadm_fail get-logpage nvmeadm_fail get-logpage health nvmeadm_fail get-logpage health health nvmeadm_fail get-logpage $nt_dev nvmeadm_fail get-logpage $nt_dev,$nt_dev/1 nvmeadm_fail get-logpage $nt_dev $nt_dev nvmeadm_fail get-logpage $nt_dev sephiorth nvmeadm_fail get-logpage $nt_dev health sephiorth nvmeadm_fail get-logpage $nt_dev health,error nvmeadm_fail list-features nvmeadm_fail list-features -a nvmeadm_fail list-features -o csi nvmeadm_fail list-features -H nvmeadm_fail list-features -p nvmeadm_fail list-features -p $nt_dev nvmeadm_fail list-features -o magicite $nt_dev nvmeadm_fail list-features -o csi materia nvmeadm_fail list-features $nt_dev $nt_dev nvmeadm_fail list-features $nt_dev/1 $nt_dev/1 nvmeadm_fail list-features $nt_dev/1 aerith nvmeadm_fail list-features $nt_dev aerith arb temp nvmeadm_fail get-features nvmeadm_fail get-features $nt_dev/cid nvmeadm_fail get-features vincent nvmeadm_fail get-features $nt_dev range nvmeadm_fail get-features $nt_dev/1 temp nvmeadm_fail get-features $nt_dev temp,tifa nvmeadm_fail get-features $nt_dev temp cloud nvmeadm_fail list-firmware nvmeadm_fail list-firmware -t nvmeadm_fail list-firmware $nt_dev/1 nvmeadm_fail list-firmware $nt_dev/squall nvmeadm_fail list-firmware $nt_dev rinoa # # Tests that we expect to pass in some form. # nvmeadm_pass list nvmeadm_pass list $nt_dev nvmeadm_pass list $nt_dev/1 nvmeadm_pass list $nt_dev,$nt_dev/1 nvmeadm_pass list -p -o model,serial $nt_dev nvmeadm_pass list -p -o model,serial $nt_dev/1 nvmeadm_pass list -p -o model,serial $nt_dev/1,$nt_dev nvmeadm_pass list -c nvmeadm_pass list -c $nt_dev nvmeadm_pass list -c $nt_dev/1 nvmeadm_pass list -c $nt_dev,$nt_dev/1 nvmeadm_pass list -c -p -o model,serial $nt_dev nvmeadm_pass list -c -p -o model,serial $nt_dev/1 nvmeadm_pass list -c -p -o model,serial $nt_dev/1,$nt_dev nvmeadm_pass identify $nt_dev nvmeadm_pass identify $nt_dev/1 nvmeadm_pass identify $nt_dev,$nt_dev/1 nvmeadm_pass identify $nt_dev,$nt_dev nvmeadm_pass identify $nt_dev,$nt_dev/1,$nt_dev nvmeadm_ns identify -C $nt_dev nvmeadm_ns identify -c $nt_dev nvmeadm_pv1v3 identify -d $nt_dev/1 nvmeadm_pv1v1 identify -n $nt_dev nvmeadm_ns identify -n -a $nt_dev nvmeadm_ns identify-controller -C $nt_dev nvmeadm_ns identify-controller -c $nt_dev nvmeadm_pv1v1 identify-controller -n $nt_dev nvmeadm_ns identify-controller -n -a $nt_dev # # All of our list- and get-logpage tests strictly use the 3 NVMe 1.0 log pages: # error, health, firmware. Note: NVMe 1.0 did not define any namespace-specific # log pages, the health log page was changed later. Therefore there are no tests # specific to solely namespace scope right now. # nvmeadm_pass list-logpages $nt_dev nvmeadm_pass list-logpages -H $nt_dev nvmeadm_pass list-logpages -o device $nt_dev nvmeadm_pass list-logpages -H -o device $nt_dev nvmeadm_pass list-logpages -o \ device,name,desc,scope,fields,csi,lid,impl,size,minsize,sources,kind $nt_dev nvmeadm_pass list-logpages -p -o lid $nt_dev nvmeadm_pass list-logpages -H -p -o lid $nt_dev nvmeadm_pass list-logpages -s controller $nt_dev nvmeadm_pass list-logpages -s controller -H $nt_dev nvmeadm_pass list-logpages -s controller -H -o device $nt_dev nvmeadm_pass list-logpages -s controller -o \ device,name,desc,scope,fields,csi,lid,impl,size,minsize,sources,kind $nt_dev nvmeadm_pass list-logpages -s controller -p -o lid $nt_dev nvmeadm_pass list-logpages -s controller,nvm $nt_dev nvmeadm_pass list-logpages -s controller,nvm,ns $nt_dev nvmeadm_pass list-logpages $nt_dev,$nt_dev nvmeadm_pass list-logpages $nt_dev error nvmeadm_pass list-logpages $nt_dev health nvmeadm_pass list-logpages -a $nt_dev nvmeadm_pass list-logpages -a $nt_dev health nvmeadm_pass list-logpages -s controller $nt_dev health nvmeadm_pass get-logpage $nt_dev health nvmeadm_pass get-logpage $nt_dev firmware nvmeadm_pass get-logpage $nt_dev,$nt_dev firmware nvmeadm_pass list-features $nt_dev nvmeadm_pass list-features -H $nt_dev nvmeadm_pass list-features -o device $nt_dev nvmeadm_pass list-features -p -o device,impl $nt_dev nvmeadm_pass list-features -o \ device,short,spec,fid,scope,kind,csi,flags,get-in,get-out,set-out,datalen \ $nt_dev nvmeadm_pass list-features -a $nt_dev nvmeadm_pass list-features $nt_dev/1 nvmeadm_pass list-features -H $nt_dev/1 nvmeadm_pass list-features -o short,fid $nt_dev/1 nvmeadm_pass list-features -p -o device,impl $nt_dev/1 nvmeadm_pass list-features -o \ device,short,spec,fid,scope,kind,csi,flags,get-in,get-out,set-out,datalen \ $nt_dev/1 nvmeadm_pass list-features -a $nt_dev/1 nvmeadm_pass list-features $nt_dev,$nt_dev/1 nvmeadm_pass list-features $nt_dev,$nt_dev/1,$nt_dev nvmeadm_pass list-features $nt_dev pm nvmeadm_pass list-features $nt_dev arbitration nvmeadm_pass list-features $nt_dev Arbitration nvmeadm_pass list-features $nt_dev pm Arbitration temp # # If you find a get-features without arguments is causing issues, please feel # free to remove this test. # nvmeadm_pass get-features $nt_dev nvmeadm_pass get-features $nt_dev temp nvmeadm_pass get-features $nt_dev temp,vector nvmeadm_pass get-features $nt_dev,$nt_dev arb nvmeadm_pass list-firmware $nt_dev # # Here we come back and use bad controller names that should not work. # These specifically do not rely on $nt_dev. # if (( nt_exit == 0 )); then printf "All tests passed successfully!\n" else printf "%u tests failed!\n" "$nt_fail" fi exit $nt_exit