xref: /illumos-gate/usr/src/test/nvme-tests/tests/nvmeadm/nvmeadm_feat.ksh (revision 564eeb7d65973f1d64a5390ff477b689707e9daf)
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