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 2026 Oxide Computer Company 15# 16 17# 18# Test various nvmeadm(8) driven set-feature related activity. This is run in 19# the OCP destructive test set, meaning we can assume that we have certain OCP 20# features present to try to set. The main goal is to test all our parsing. 21# 22# When we can get a feature and list specific fields from it in a 23# machine-parsable way, we should come back and add a basic round-trip test for 24# this. 25# 26 27export LC_ALL=C.UTF-8 28export LD_PRELOAD=libumem.so 29export UMEM_DEBUG=default 30unalias -a 31set -o pipefail 32 33nt_prog=${NVMEADM:-"/usr/sbin/nvmeadm"} 34nt_arg0=$(basename $0) 35nt_exit=0 36nt_fail=0 37nt_dev="$NVME_TEST_DEVICE" 38 39function warn 40{ 41 typeset msg="$*" 42 [[ -z "$msg" ]] && msg="failed" 43 echo "TEST FAILED: $msg" >&2 44 nt_exit=1 45 ((nt_fail++)) 46} 47 48function fatal 49{ 50 typeset msg="$*" 51 [[ -z "$msg" ]] && msg="failed" 52 echo "$nt_arg0: $msg" >&2 53 exit 1 54} 55 56function check_feat 57{ 58 typeset feat="$1" 59 typeset out=$($nt_prog list-features -po impl $nt_dev $feat) 60 61 if [[ "$out" != "yes" ]]; then 62 fatal "INTERNAL TEST FAILURE: missing required feature $feat" 63 fi 64} 65 66function plp_fail 67{ 68 typeset ret 69 70 "$nt_prog" set-feature $@ "$nt_dev" ocp/plphealth 2>/dev/null \ 71 1>/dev/null 72 73 ret=$? 74 if (( ret == 0 )); then 75 warn "should have failed with args $@, but passed" 76 elif (( ret != 255 )); then 77 warn "$@ exited with $ret, but expected 255" 78 else 79 printf "TEST PASSED: program failed: set-feature %s %s %s\n" \ 80 "$*" "$nt_dev" "ocp/plphealth" 81 fi 82} 83 84function errinj_fail 85{ 86 typeset ret 87 88 "$nt_prog" set-feature $@ "$nt_dev" ocp/errinj 2>/dev/null \ 89 1>/dev/null 90 91 ret=$? 92 if (( ret == 0 )); then 93 warn "should have failed with args $@, but passed" 94 elif (( ret != 255 )); then 95 warn "$@ exited with $ret, but expected 255" 96 else 97 printf "TEST PASSED: program failed: set-feature %s %s %s\n" \ 98 "$*" "$nt_dev" "ocp/errinj" 99 fi 100 101} 102 103function nvmeadm_pass 104{ 105 if ! "$nt_prog" $@ 2>/dev/null 1>/dev/null; then 106 warn "should have passed with args $@, but failed" 107 return; 108 fi 109 110 printf "TEST PASSED: %s %s exited successfully\n" "$nt_prog" "$*" 111} 112 113if [[ -n "$NVMEADM" ]]; then 114 nt_prog="$NVMEADM" 115fi 116 117# 118# Verify the wrappers set our device. 119# 120if [[ -z "$nt_dev" ]]; then 121 fatal "missing disk definition for \$NVME_TEST_DEVICE" 122fi 123 124check_feat ocp/plphealth 125check_feat ocp/errinj 126 127# 128# Verify a variety of parsing errors: 129# 130# - Invalid number formats 131# - Fields that aren't allowed to be used with a given feature 132# - Missing option combinations 133# 134plp_fail 135plp_fail -v foo 136plp_fail -v -3 137plp_fail -v 0x7777world 138plp_fail -v 123.456 139plp_fail -v 0x12346789abcdef123456789abcdef 140plp_fail -v 0xf --cdw12 foo 141plp_fail -v 0xf --cdw12 -3 142plp_fail -v 0xf --cdw12 0x7777world 143plp_fail -v 0xf --cdw12 123.456 144plp_fail -v 0xf --cdw12 0x23 145plp_fail -v 0xf --cdw13 foo 146plp_fail -v 0xf --cdw13 -3 147plp_fail -v 0xf --cdw13 0x7777world 148plp_fail -v 0xf --cdw13 123.456 149plp_fail -v 0xf --cdw13 0x23 150plp_fail -v 0xf --cdw15 foo 151plp_fail -v 0xf --cdw15 -3 152plp_fail -v 0xf --cdw15 0x7777world 153plp_fail -v 0xf --cdw15 123.456 154plp_fail -v 0xf --cdw15 0x23 155plp_fail -v 0xf -I foobar 156plp_fail -v 0xf -I 0,1,2 157plp_fail -v 0xf -I 0x 158plp_fail -v 0xf -I data,nonsense 159 160# 161# To test the offset / length errors we use the error injection which will treat 162# a zeroed data payload as a means to clear this, meaning we can just use 163# /dev/zero and vary the length. The expected length for the feature is 4k. 164# 165errinj_fail -v 1 166errinj_fail -v 0 -i /dev/null 167errinj_fail -v 0 -l 4096 168errinj_fail -v 0 -i /dev/null -l foobar 169errinj_fail -v 0 -i /dev/null -l 0x12.34 170errinj_fail -v 0 -i /dev/null -l -23 171errinj_fail -v 0 -i /dev/null -l 123abc 172errinj_fail -v 0 -l 4096 -i /enoent 173 174# 175# Finally use the fact that this error injection is a set features and send the 176# clear command via /dev/null. 177# 178nvmeadm_pass set-feature -v 0 -i /dev/null -l 0x1000 "$nt_dev" ocp/errinj 179nvmeadm_pass set-feature --cdw11 0 --input /dev/null --length 0x1000 "$nt_dev" \ 180 ocp/errinj 181 182if (( nt_exit == 0 )); then 183 printf "All tests passed successfully!\n" 184else 185 printf "%u tests failed!\n" "$nt_fail" 186fi 187 188exit $nt_exit 189