1*508a0e8cSRob Johnston /*
2*508a0e8cSRob Johnston  * This file and its contents are supplied under the terms of the
3*508a0e8cSRob Johnston  * Common Development and Distribution License ("CDDL"), version 1.0.
4*508a0e8cSRob Johnston  * You may only use this file in accordance with the terms of version
5*508a0e8cSRob Johnston  * 1.0 of the CDDL.
6*508a0e8cSRob Johnston  *
7*508a0e8cSRob Johnston  * A full copy of the text of the CDDL should have accompanied this
8*508a0e8cSRob Johnston  * source.  A copy of the CDDL is also available via the Internet at
9*508a0e8cSRob Johnston  * http://www.illumos.org/license/CDDL.
10*508a0e8cSRob Johnston  */
11*508a0e8cSRob Johnston 
12*508a0e8cSRob Johnston /*
13*508a0e8cSRob Johnston  * Copyright 2019 Joyent, Inc.
14*508a0e8cSRob Johnston  */
15*508a0e8cSRob Johnston #include <stdio.h>
16*508a0e8cSRob Johnston #include <stdlib.h>
17*508a0e8cSRob Johnston #include <errno.h>
18*508a0e8cSRob Johnston #include <fcntl.h>
19*508a0e8cSRob Johnston #include <libnvpair.h>
20*508a0e8cSRob Johnston #include <string.h>
21*508a0e8cSRob Johnston #include <stropts.h>
22*508a0e8cSRob Johnston #include <unistd.h>
23*508a0e8cSRob Johnston #include <sys/debug.h>
24*508a0e8cSRob Johnston #include <sys/ddi_ufm.h>
25*508a0e8cSRob Johnston #include <sys/types.h>
26*508a0e8cSRob Johnston #include <sys/varargs.h>
27*508a0e8cSRob Johnston 
28*508a0e8cSRob Johnston #include "ufmtest.h"
29*508a0e8cSRob Johnston 
30*508a0e8cSRob Johnston #define	ERRNO_ANY	-1
31*508a0e8cSRob Johnston #define	UFMTEST_DEV	"/pseudo/ufmtest@0"
32*508a0e8cSRob Johnston 
33*508a0e8cSRob Johnston static const char *pname;
34*508a0e8cSRob Johnston 
35*508a0e8cSRob Johnston struct ufm_test_state {
36*508a0e8cSRob Johnston 	uint_t		ufts_n_run;
37*508a0e8cSRob Johnston 	uint_t		ufts_n_passes;
38*508a0e8cSRob Johnston 	uint_t		ufts_n_fails;
39*508a0e8cSRob Johnston 	int		ufts_ufm_fd;
40*508a0e8cSRob Johnston 	int		ufts_ufmtest_fd;
41*508a0e8cSRob Johnston };
42*508a0e8cSRob Johnston 
43*508a0e8cSRob Johnston #define	MAX_IMAGES	5
44*508a0e8cSRob Johnston #define	MAX_SLOTS	5
45*508a0e8cSRob Johnston #define	MAX_STR		128
46*508a0e8cSRob Johnston struct ufm_test_slot_data {
47*508a0e8cSRob Johnston 	const char			us_vers[MAX_STR];
48*508a0e8cSRob Johnston 	int				us_attrs;
49*508a0e8cSRob Johnston 	int				us_nmisc;
50*508a0e8cSRob Johnston };
51*508a0e8cSRob Johnston 
52*508a0e8cSRob Johnston struct ufm_test_img_data {
53*508a0e8cSRob Johnston 	const char			ui_desc[MAX_STR];
54*508a0e8cSRob Johnston 	int				ui_nslots;
55*508a0e8cSRob Johnston 	int				ui_nmisc;
56*508a0e8cSRob Johnston 	struct ufm_test_slot_data	ui_slots[MAX_SLOTS];
57*508a0e8cSRob Johnston };
58*508a0e8cSRob Johnston 
59*508a0e8cSRob Johnston struct ufm_test_data {
60*508a0e8cSRob Johnston 	uint_t				ud_nimages;
61*508a0e8cSRob Johnston 	struct ufm_test_img_data	ud_images[MAX_IMAGES];
62*508a0e8cSRob Johnston };
63*508a0e8cSRob Johnston 
64*508a0e8cSRob Johnston #define	NO_SLOT	{"", -1, -1}
65*508a0e8cSRob Johnston #define	NO_IMG	{"", -1, -1, {NO_SLOT, NO_SLOT, NO_SLOT, NO_SLOT, NO_SLOT}}
66*508a0e8cSRob Johnston 
67*508a0e8cSRob Johnston /*
68*508a0e8cSRob Johnston  * 3 images w\
69*508a0e8cSRob Johnston  * - 1 slot
70*508a0e8cSRob Johnston  * - 2 slots (1st active)
71*508a0e8cSRob Johnston  * - 3 slots (1st active, 3rd empty)
72*508a0e8cSRob Johnston  */
73*508a0e8cSRob Johnston const struct ufm_test_data fw_data1 = {
74*508a0e8cSRob Johnston 	3,
75*508a0e8cSRob Johnston 	{
76*508a0e8cSRob Johnston 	{"fw image 1", 1, 0, {
77*508a0e8cSRob Johnston 	{"1.0", 4, 0 }, NO_SLOT, NO_SLOT, NO_SLOT, NO_SLOT }},
78*508a0e8cSRob Johnston 	{"fw image 2", 2, 0, {
79*508a0e8cSRob Johnston 	{"1.0", 4, 0 }, {"1.1", 0, 0}, NO_SLOT, NO_SLOT, NO_SLOT }},
80*508a0e8cSRob Johnston 	{"fw image 3", 3, 0, {
81*508a0e8cSRob Johnston 	{"1.0", 4, 0 }, {"1.1", 0, 0}, {"", 8, 0}, NO_SLOT, NO_SLOT }},
82*508a0e8cSRob Johnston 	NO_IMG,
83*508a0e8cSRob Johnston 	NO_IMG
84*508a0e8cSRob Johnston 	}
85*508a0e8cSRob Johnston };
86*508a0e8cSRob Johnston 
87*508a0e8cSRob Johnston /*
88*508a0e8cSRob Johnston  * Generate an ISO 8601 timestamp
89*508a0e8cSRob Johnston  */
90*508a0e8cSRob Johnston static void
get_timestamp(char * buf,size_t bufsize)91*508a0e8cSRob Johnston get_timestamp(char *buf, size_t bufsize)
92*508a0e8cSRob Johnston {
93*508a0e8cSRob Johnston 	time_t utc_time;
94*508a0e8cSRob Johnston 	struct tm *p_tm;
95*508a0e8cSRob Johnston 
96*508a0e8cSRob Johnston 	(void) time(&utc_time);
97*508a0e8cSRob Johnston 	p_tm = localtime(&utc_time);
98*508a0e8cSRob Johnston 
99*508a0e8cSRob Johnston 	(void) strftime(buf, bufsize, "%FT%TZ", p_tm);
100*508a0e8cSRob Johnston }
101*508a0e8cSRob Johnston 
102*508a0e8cSRob Johnston /* PRINTFLIKE1 */
103*508a0e8cSRob Johnston static void
logmsg(const char * format,...)104*508a0e8cSRob Johnston logmsg(const char *format, ...)
105*508a0e8cSRob Johnston {
106*508a0e8cSRob Johnston 	char timestamp[128];
107*508a0e8cSRob Johnston 	va_list ap;
108*508a0e8cSRob Johnston 
109*508a0e8cSRob Johnston 	get_timestamp(timestamp, sizeof (timestamp));
110*508a0e8cSRob Johnston 	(void) fprintf(stdout, "%s ", timestamp);
111*508a0e8cSRob Johnston 	va_start(ap, format);
112*508a0e8cSRob Johnston 	(void) vfprintf(stdout, format, ap);
113*508a0e8cSRob Johnston 	va_end(ap);
114*508a0e8cSRob Johnston 	(void) fprintf(stdout, "\n");
115*508a0e8cSRob Johnston 	(void) fflush(stdout);
116*508a0e8cSRob Johnston }
117*508a0e8cSRob Johnston 
118*508a0e8cSRob Johnston static int
do_test_setup(struct ufm_test_state * tst_state)119*508a0e8cSRob Johnston do_test_setup(struct ufm_test_state *tst_state)
120*508a0e8cSRob Johnston {
121*508a0e8cSRob Johnston 	if ((tst_state->ufts_ufm_fd = open(DDI_UFM_DEV, O_RDONLY)) < 0) {
122*508a0e8cSRob Johnston 		logmsg("failed to open %s (%s)", DDI_UFM_DEV,
123*508a0e8cSRob Johnston 		    strerror(errno));
124*508a0e8cSRob Johnston 		return (-1);
125*508a0e8cSRob Johnston 	}
126*508a0e8cSRob Johnston 	if ((tst_state->ufts_ufmtest_fd = open("/dev/ufmtest", O_RDONLY)) < 0) {
127*508a0e8cSRob Johnston 		logmsg("failed to open /dev/ufmtest (%s)",
128*508a0e8cSRob Johnston 		    strerror(errno));
129*508a0e8cSRob Johnston 		return (0);
130*508a0e8cSRob Johnston 	}
131*508a0e8cSRob Johnston 	return (0);
132*508a0e8cSRob Johnston }
133*508a0e8cSRob Johnston 
134*508a0e8cSRob Johnston static void
free_nvlist_arr(nvlist_t ** nvlarr,uint_t nelems)135*508a0e8cSRob Johnston free_nvlist_arr(nvlist_t **nvlarr, uint_t nelems)
136*508a0e8cSRob Johnston {
137*508a0e8cSRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
138*508a0e8cSRob Johnston 		if (nvlarr[i] != NULL)
139*508a0e8cSRob Johnston 			nvlist_free(nvlarr[i]);
140*508a0e8cSRob Johnston 	}
141*508a0e8cSRob Johnston 	free(nvlarr);
142*508a0e8cSRob Johnston }
143*508a0e8cSRob Johnston 
144*508a0e8cSRob Johnston static int
do_setfw(struct ufm_test_state * tst_state,const struct ufm_test_data * fwdata)145*508a0e8cSRob Johnston do_setfw(struct ufm_test_state *tst_state, const struct ufm_test_data *fwdata)
146*508a0e8cSRob Johnston {
147*508a0e8cSRob Johnston 	ufmtest_ioc_setfw_t ioc = { 0 };
148*508a0e8cSRob Johnston 	nvlist_t *nvl = NULL, **images = NULL, **slots = NULL;
149*508a0e8cSRob Johnston 	int ret = -1;
150*508a0e8cSRob Johnston 
151*508a0e8cSRob Johnston 	if ((images = calloc(sizeof (nvlist_t *), fwdata->ud_nimages)) == NULL)
152*508a0e8cSRob Johnston 		return (-1);
153*508a0e8cSRob Johnston 
154*508a0e8cSRob Johnston 	for (uint_t i = 0; i < fwdata->ud_nimages; i++) {
155*508a0e8cSRob Johnston 		if (nvlist_alloc(&images[i], NV_UNIQUE_NAME, 0) != 0 ||
156*508a0e8cSRob Johnston 		    nvlist_add_string(images[i], DDI_UFM_NV_IMAGE_DESC,
157*508a0e8cSRob Johnston 		    fwdata->ud_images[i].ui_desc) != 0) {
158*508a0e8cSRob Johnston 			goto out;
159*508a0e8cSRob Johnston 		}
160*508a0e8cSRob Johnston 		if ((slots = calloc(sizeof (nvlist_t *),
161*508a0e8cSRob Johnston 		    fwdata->ud_images[i].ui_nslots)) == NULL) {
162*508a0e8cSRob Johnston 			goto out;
163*508a0e8cSRob Johnston 		}
164*508a0e8cSRob Johnston 
165*508a0e8cSRob Johnston 		for (int s = 0; s < fwdata->ud_images[i].ui_nslots; s++) {
166*508a0e8cSRob Johnston 			if (nvlist_alloc(&slots[s], NV_UNIQUE_NAME, 0) != 0 ||
167*508a0e8cSRob Johnston 			    nvlist_add_string(slots[s], DDI_UFM_NV_SLOT_VERSION,
168*508a0e8cSRob Johnston 			    fwdata->ud_images[i].ui_slots[s].us_vers) != 0 ||
169*508a0e8cSRob Johnston 			    nvlist_add_uint32(slots[s], DDI_UFM_NV_SLOT_ATTR,
170*508a0e8cSRob Johnston 			    fwdata->ud_images[i].ui_slots[s].us_attrs) != 0) {
171*508a0e8cSRob Johnston 
172*508a0e8cSRob Johnston 				free_nvlist_arr(slots,
173*508a0e8cSRob Johnston 				    fwdata->ud_images[i].ui_nslots);
174*508a0e8cSRob Johnston 				goto out;
175*508a0e8cSRob Johnston 			}
176*508a0e8cSRob Johnston 		}
177*508a0e8cSRob Johnston 
178*508a0e8cSRob Johnston 		if (nvlist_add_nvlist_array(images[i], DDI_UFM_NV_IMAGE_SLOTS,
179*508a0e8cSRob Johnston 		    slots, fwdata->ud_images[i].ui_nslots) != 0) {
180*508a0e8cSRob Johnston 			free_nvlist_arr(slots, fwdata->ud_images[i].ui_nslots);
181*508a0e8cSRob Johnston 			goto out;
182*508a0e8cSRob Johnston 		}
183*508a0e8cSRob Johnston 		free_nvlist_arr(slots, fwdata->ud_images[i].ui_nslots);
184*508a0e8cSRob Johnston 	}
185*508a0e8cSRob Johnston 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
186*508a0e8cSRob Johnston 	    nvlist_add_nvlist_array(nvl, DDI_UFM_NV_IMAGES, images,
187*508a0e8cSRob Johnston 	    fwdata->ud_nimages) != 0) {
188*508a0e8cSRob Johnston 		goto out;
189*508a0e8cSRob Johnston 	}
190*508a0e8cSRob Johnston 
191*508a0e8cSRob Johnston 	if (nvlist_size(nvl, &ioc.utsw_bufsz, NV_ENCODE_NATIVE) != 0 ||
192*508a0e8cSRob Johnston 	    (ioc.utsw_buf = malloc(ioc.utsw_bufsz)) == NULL ||
193*508a0e8cSRob Johnston 	    nvlist_pack(nvl, &ioc.utsw_buf, &ioc.utsw_bufsz, NV_ENCODE_NATIVE,
194*508a0e8cSRob Johnston 	    0) != 0) {
195*508a0e8cSRob Johnston 		goto out;
196*508a0e8cSRob Johnston 	}
197*508a0e8cSRob Johnston 
198*508a0e8cSRob Johnston 	if (ioctl(tst_state->ufts_ufmtest_fd, UFMTEST_IOC_SET_FW, &ioc) < 0) {
199*508a0e8cSRob Johnston 		logmsg("UFMTEST_IOC_SET_FW ioctl failed (%s)",
200*508a0e8cSRob Johnston 		    strerror(errno));
201*508a0e8cSRob Johnston 		return (-1);
202*508a0e8cSRob Johnston 	}
203*508a0e8cSRob Johnston 	ret = 0;
204*508a0e8cSRob Johnston out:
205*508a0e8cSRob Johnston 	free_nvlist_arr(images, fwdata->ud_nimages);
206*508a0e8cSRob Johnston 	nvlist_free(nvl);
207*508a0e8cSRob Johnston 	free(ioc.utsw_buf);
208*508a0e8cSRob Johnston 
209*508a0e8cSRob Johnston 	return (ret);
210*508a0e8cSRob Johnston }
211*508a0e8cSRob Johnston 
212*508a0e8cSRob Johnston static int
do_toggle_fails(struct ufm_test_state * tst_state,uint32_t fail_flags)213*508a0e8cSRob Johnston do_toggle_fails(struct ufm_test_state *tst_state, uint32_t fail_flags)
214*508a0e8cSRob Johnston {
215*508a0e8cSRob Johnston 	ufmtest_ioc_fails_t ioc = { 0 };
216*508a0e8cSRob Johnston 
217*508a0e8cSRob Johnston 	ioc.utfa_flags = fail_flags;
218*508a0e8cSRob Johnston 
219*508a0e8cSRob Johnston 	if (ioctl(tst_state->ufts_ufmtest_fd, UFMTEST_IOC_TOGGLE_FAILS,
220*508a0e8cSRob Johnston 	    &ioc) < 0) {
221*508a0e8cSRob Johnston 		logmsg("UFMTEST_IOC_TOGGLE_FAILS ioctl failed (%s)",
222*508a0e8cSRob Johnston 		    strerror(errno));
223*508a0e8cSRob Johnston 		return (1);
224*508a0e8cSRob Johnston 	}
225*508a0e8cSRob Johnston 	return (0);
226*508a0e8cSRob Johnston }
227*508a0e8cSRob Johnston 
228*508a0e8cSRob Johnston static int
do_update(struct ufm_test_state * tst_state)229*508a0e8cSRob Johnston do_update(struct ufm_test_state *tst_state)
230*508a0e8cSRob Johnston {
231*508a0e8cSRob Johnston 	if (ioctl(tst_state->ufts_ufmtest_fd, UFMTEST_IOC_DO_UPDATE,
232*508a0e8cSRob Johnston 	    NULL) < 0) {
233*508a0e8cSRob Johnston 		logmsg("UFMTEST_IOC_DO_UPDATE ioctl failed (%s)",
234*508a0e8cSRob Johnston 		    strerror(errno));
235*508a0e8cSRob Johnston 		return (1);
236*508a0e8cSRob Johnston 	}
237*508a0e8cSRob Johnston 	return (0);
238*508a0e8cSRob Johnston }
239*508a0e8cSRob Johnston 
240*508a0e8cSRob Johnston static int
try_open(int oflag,int exp_errno)241*508a0e8cSRob Johnston try_open(int oflag, int exp_errno)
242*508a0e8cSRob Johnston {
243*508a0e8cSRob Johnston 	int fd;
244*508a0e8cSRob Johnston 
245*508a0e8cSRob Johnston 	fd = open(DDI_UFM_DEV, oflag);
246*508a0e8cSRob Johnston 	if (fd != -1) {
247*508a0e8cSRob Johnston 		logmsg("FAIL: expected open(2) to return -1");
248*508a0e8cSRob Johnston 		(void) close(fd);
249*508a0e8cSRob Johnston 		return (-1);
250*508a0e8cSRob Johnston 	}
251*508a0e8cSRob Johnston 	if (errno != exp_errno) {
252*508a0e8cSRob Johnston 		logmsg("FAIL: expected errno to be set to %u (%s)\n"
253*508a0e8cSRob Johnston 		    "actual errno was %u (%s)", exp_errno, strerror(exp_errno),
254*508a0e8cSRob Johnston 		    errno, strerror(errno));
255*508a0e8cSRob Johnston 		return (-1);
256*508a0e8cSRob Johnston 	}
257*508a0e8cSRob Johnston 	return (0);
258*508a0e8cSRob Johnston }
259*508a0e8cSRob Johnston 
260*508a0e8cSRob Johnston static void
do_negative_open_tests(struct ufm_test_state * tst_state)261*508a0e8cSRob Johnston do_negative_open_tests(struct ufm_test_state *tst_state)
262*508a0e8cSRob Johnston {
263*508a0e8cSRob Johnston 	/*
264*508a0e8cSRob Johnston 	 * Assertion: Opening /dev/ufm in write-only mode will fail with errno
265*508a0e8cSRob Johnston 	 * set to EINVAL;
266*508a0e8cSRob Johnston 	 */
267*508a0e8cSRob Johnston 	logmsg("TEST ufm_open_negative_001: Open %s in write-only mode",
268*508a0e8cSRob Johnston 	    DDI_UFM_DEV);
269*508a0e8cSRob Johnston 	if (try_open(O_WRONLY, EINVAL) != 0)
270*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
271*508a0e8cSRob Johnston 	else
272*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
273*508a0e8cSRob Johnston 
274*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
275*508a0e8cSRob Johnston 
276*508a0e8cSRob Johnston 	/*
277*508a0e8cSRob Johnston 	 * Assertion: Opening /dev/ufm in read-write mode will fail with errno
278*508a0e8cSRob Johnston 	 * set to EINVAL;
279*508a0e8cSRob Johnston 	 */
280*508a0e8cSRob Johnston 	logmsg("TEST ufm_open_negative_002: Open %s in read-write mode",
281*508a0e8cSRob Johnston 	    DDI_UFM_DEV);
282*508a0e8cSRob Johnston 	if (try_open(O_RDWR, EINVAL) != 0)
283*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
284*508a0e8cSRob Johnston 	else
285*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
286*508a0e8cSRob Johnston 
287*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
288*508a0e8cSRob Johnston 
289*508a0e8cSRob Johnston 	/*
290*508a0e8cSRob Johnston 	 * Assertion: Opening /dev/ufm in exclusive mode will fail with errno
291*508a0e8cSRob Johnston 	 * set to EINVAL;
292*508a0e8cSRob Johnston 	 */
293*508a0e8cSRob Johnston 	logmsg("TEST ufm_open_negative_003: Open %s in exclusive mode",
294*508a0e8cSRob Johnston 	    DDI_UFM_DEV);
295*508a0e8cSRob Johnston 	if (try_open(O_RDONLY | O_EXCL, EINVAL) != 0)
296*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
297*508a0e8cSRob Johnston 	else
298*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
299*508a0e8cSRob Johnston 
300*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
301*508a0e8cSRob Johnston 
302*508a0e8cSRob Johnston 	/*
303*508a0e8cSRob Johnston 	 * Assertion: Opening /dev/ufm in non-blocking mode will fail with errno
304*508a0e8cSRob Johnston 	 * set to EINVAL;
305*508a0e8cSRob Johnston 	 */
306*508a0e8cSRob Johnston 	logmsg("TEST ufm_open_negative_004: Open %s in non-block mode",
307*508a0e8cSRob Johnston 	    DDI_UFM_DEV);
308*508a0e8cSRob Johnston 	if (try_open(O_RDONLY | O_NONBLOCK, EINVAL) != 0)
309*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
310*508a0e8cSRob Johnston 	else
311*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
312*508a0e8cSRob Johnston 
313*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
314*508a0e8cSRob Johnston 
315*508a0e8cSRob Johnston 	/*
316*508a0e8cSRob Johnston 	 * Assertion: Opening /dev/ufm in no-delay mode will fail with errno
317*508a0e8cSRob Johnston 	 * set to EINVAL;
318*508a0e8cSRob Johnston 	 */
319*508a0e8cSRob Johnston 	logmsg("TEST ufm_open_negative_005: Open %s in ndelay mode",
320*508a0e8cSRob Johnston 	    DDI_UFM_DEV);
321*508a0e8cSRob Johnston 	if (try_open(O_RDONLY | O_NDELAY, EINVAL) != 0)
322*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
323*508a0e8cSRob Johnston 	else
324*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
325*508a0e8cSRob Johnston 
326*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
327*508a0e8cSRob Johnston }
328*508a0e8cSRob Johnston 
329*508a0e8cSRob Johnston 
330*508a0e8cSRob Johnston static int
try_ioctl(int fd,int cmd,void * arg,int exp_errno)331*508a0e8cSRob Johnston try_ioctl(int fd, int cmd, void *arg, int exp_errno)
332*508a0e8cSRob Johnston {
333*508a0e8cSRob Johnston 	int ret;
334*508a0e8cSRob Johnston 
335*508a0e8cSRob Johnston 	ret = ioctl(fd, cmd, arg);
336*508a0e8cSRob Johnston 	if (ret != -1) {
337*508a0e8cSRob Johnston 		logmsg("FAIL: expected ioctl(2) to return -1");
338*508a0e8cSRob Johnston 		(void) close(fd);
339*508a0e8cSRob Johnston 		return (-1);
340*508a0e8cSRob Johnston 	}
341*508a0e8cSRob Johnston 	if (exp_errno != ERRNO_ANY && errno != exp_errno) {
342*508a0e8cSRob Johnston 		logmsg("FAIL: expected errno to be set to %u (%s)\n"
343*508a0e8cSRob Johnston 		    "actual errno was %u (%s)", exp_errno, strerror(exp_errno),
344*508a0e8cSRob Johnston 		    errno, strerror(errno));
345*508a0e8cSRob Johnston 		return (-1);
346*508a0e8cSRob Johnston 	}
347*508a0e8cSRob Johnston 	return (0);
348*508a0e8cSRob Johnston }
349*508a0e8cSRob Johnston 
350*508a0e8cSRob Johnston /*
351*508a0e8cSRob Johnston  * These are a set of negative test cases to verify the correctness and
352*508a0e8cSRob Johnston  * robustness of the DDI UFM ioctl interface.
353*508a0e8cSRob Johnston  */
354*508a0e8cSRob Johnston static void
do_negative_ioctl_tests(struct ufm_test_state * tst_state)355*508a0e8cSRob Johnston do_negative_ioctl_tests(struct ufm_test_state *tst_state)
356*508a0e8cSRob Johnston {
357*508a0e8cSRob Johnston 	ufm_ioc_getcaps_t ugc = { 0 };
358*508a0e8cSRob Johnston 	ufm_ioc_bufsz_t ubz = { 0 };
359*508a0e8cSRob Johnston 	ufm_ioc_report_t urep = { 0 };
360*508a0e8cSRob Johnston 	size_t reportsz;
361*508a0e8cSRob Johnston 	char *buf;
362*508a0e8cSRob Johnston 	uint_t i, j;
363*508a0e8cSRob Johnston 
364*508a0e8cSRob Johnston 	uint8_t not_ascii[MAXPATHLEN];
365*508a0e8cSRob Johnston 	char no_nul[MAXPATHLEN];
366*508a0e8cSRob Johnston 
367*508a0e8cSRob Johnston 	for (uint_t i = 0; i < MAXPATHLEN; i++)
368*508a0e8cSRob Johnston 		no_nul[i] = '%';
369*508a0e8cSRob Johnston 
370*508a0e8cSRob Johnston 	CTASSERT(MAXPATHLEN > 129);
371*508a0e8cSRob Johnston 	for (i = 0, j = 128; j <= 256; i++, j++)
372*508a0e8cSRob Johnston 		not_ascii[i] = j;
373*508a0e8cSRob Johnston 
374*508a0e8cSRob Johnston 	not_ascii[i] = '\0';
375*508a0e8cSRob Johnston 
376*508a0e8cSRob Johnston 	/*
377*508a0e8cSRob Johnston 	 * Seed the test driver with a set of valid firmware data
378*508a0e8cSRob Johnston 	 */
379*508a0e8cSRob Johnston 	if (do_setfw(tst_state, &fw_data1) != 0) {
380*508a0e8cSRob Johnston 		logmsg("Failed to seed ufmtest driver with fw data");
381*508a0e8cSRob Johnston 		return;
382*508a0e8cSRob Johnston 	}
383*508a0e8cSRob Johnston 
384*508a0e8cSRob Johnston 	/*
385*508a0e8cSRob Johnston 	 * Cache the report size, and create a buffer of that size,
386*508a0e8cSRob Johnston 	 * as we'll need them for some of the tests that follow.
387*508a0e8cSRob Johnston 	 */
388*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
389*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
390*508a0e8cSRob Johnston 	if (ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz) < 0) {
391*508a0e8cSRob Johnston 		logmsg("Failed to get fw data report size");
392*508a0e8cSRob Johnston 		return;
393*508a0e8cSRob Johnston 	}
394*508a0e8cSRob Johnston 	reportsz = ubz.ufbz_size;
395*508a0e8cSRob Johnston 	if ((buf = malloc(reportsz)) == NULL) {
396*508a0e8cSRob Johnston 		logmsg("Failed to allocate %u bytes to hold report");
397*508a0e8cSRob Johnston 		return;
398*508a0e8cSRob Johnston 	}
399*508a0e8cSRob Johnston 
400*508a0e8cSRob Johnston 	/*
401*508a0e8cSRob Johnston 	 * Assertion: Specifying a DDI UFM version that is out of range in the
402*508a0e8cSRob Johnston 	 * argument to UFM_IOC_GETCAPS will fail and set errno to ENOTSUP.
403*508a0e8cSRob Johnston 	 */
404*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_001: Bad DDI UFM version (too low)");
405*508a0e8cSRob Johnston 	ugc.ufmg_version = 0;
406*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, UFMTEST_DEV, MAXPATHLEN);
407*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
408*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
409*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
410*508a0e8cSRob Johnston 	else
411*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
412*508a0e8cSRob Johnston 
413*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
414*508a0e8cSRob Johnston 
415*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_002: Bad DDI UFM version (too high)");
416*508a0e8cSRob Johnston 	ugc.ufmg_version = 999;
417*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, UFMTEST_DEV, MAXPATHLEN);
418*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
419*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
420*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
421*508a0e8cSRob Johnston 	else
422*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
423*508a0e8cSRob Johnston 
424*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
425*508a0e8cSRob Johnston 
426*508a0e8cSRob Johnston 	/*
427*508a0e8cSRob Johnston 	 * Assertion: Specifying a bad device pathname in the argument to
428*508a0e8cSRob Johnston 	 * UFM_IOC_GETCAPS will cause the ioctl to fail, but the driver will
429*508a0e8cSRob Johnston 	 * not hang or panic.
430*508a0e8cSRob Johnston 	 */
431*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_003: Bad devpath (empty)");
432*508a0e8cSRob Johnston 	ugc.ufmg_version = DDI_UFM_CURRENT_VERSION;
433*508a0e8cSRob Johnston 	ugc.ufmg_devpath[0] = '\0';
434*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
435*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
436*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
437*508a0e8cSRob Johnston 	else
438*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
439*508a0e8cSRob Johnston 
440*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
441*508a0e8cSRob Johnston 
442*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_004: Bad devpath (not a device)");
443*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, "/usr/bin/ls", MAXPATHLEN);
444*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
445*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
446*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
447*508a0e8cSRob Johnston 	else
448*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
449*508a0e8cSRob Johnston 
450*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
451*508a0e8cSRob Johnston 
452*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_005: Bad devpath (not UFM device)");
453*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, "/dev/stdout", MAXPATHLEN);
454*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
455*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
456*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
457*508a0e8cSRob Johnston 	else
458*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
459*508a0e8cSRob Johnston 
460*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
461*508a0e8cSRob Johnston 
462*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_006: Bad devpath (no NUL term)");
463*508a0e8cSRob Johnston 	(void) strncpy(ugc.ufmg_devpath, no_nul, MAXPATHLEN);
464*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
465*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
466*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
467*508a0e8cSRob Johnston 	else
468*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
469*508a0e8cSRob Johnston 
470*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
471*508a0e8cSRob Johnston 
472*508a0e8cSRob Johnston 	logmsg("TEST ufm_getcaps_negative_007: Bad devpath (not ascii str)");
473*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, (char *)not_ascii, MAXPATHLEN);
474*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
475*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
476*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
477*508a0e8cSRob Johnston 	else
478*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
479*508a0e8cSRob Johnston 
480*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
481*508a0e8cSRob Johnston 
482*508a0e8cSRob Johnston 	/*
483*508a0e8cSRob Johnston 	 * Assertion: Specifying a DDI UFM version that is out of range in the
484*508a0e8cSRob Johnston 	 * argument to UFM_IOC_REPORTSZ will fail and set errno to ENOTSUP.
485*508a0e8cSRob Johnston 	 */
486*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_001: Bad DDI UFM version (too low)");
487*508a0e8cSRob Johnston 	ubz.ufbz_version = 0;
488*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
489*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
490*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
491*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
492*508a0e8cSRob Johnston 	else
493*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
494*508a0e8cSRob Johnston 
495*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
496*508a0e8cSRob Johnston 
497*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_002: Bad DDI UFM version (too "
498*508a0e8cSRob Johnston 	    "high)");
499*508a0e8cSRob Johnston 	ubz.ufbz_version = 999;
500*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
501*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
502*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
503*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
504*508a0e8cSRob Johnston 	else
505*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
506*508a0e8cSRob Johnston 
507*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
508*508a0e8cSRob Johnston 
509*508a0e8cSRob Johnston 	/*
510*508a0e8cSRob Johnston 	 * Assertion: Specifying a bad device pathname in the argument to
511*508a0e8cSRob Johnston 	 * UFM_IOC_REPORTSZ will cause the ioctl to fail, but the driver will
512*508a0e8cSRob Johnston 	 * not hang or panic.
513*508a0e8cSRob Johnston 	 */
514*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_003: Bad devpath (empty)");
515*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
516*508a0e8cSRob Johnston 	ubz.ufbz_devpath[0] = '\0';
517*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
518*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
519*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
520*508a0e8cSRob Johnston 	else
521*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
522*508a0e8cSRob Johnston 
523*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
524*508a0e8cSRob Johnston 
525*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_004: Bad devpath (not a device)");
526*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
527*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, "/usr/bin/ls", MAXPATHLEN);
528*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
529*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
530*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
531*508a0e8cSRob Johnston 	else
532*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
533*508a0e8cSRob Johnston 
534*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
535*508a0e8cSRob Johnston 
536*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_005: Bad devpath (not UFM device)");
537*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
538*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, "/dev/stdout", MAXPATHLEN);
539*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
540*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
541*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
542*508a0e8cSRob Johnston 	else
543*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
544*508a0e8cSRob Johnston 
545*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
546*508a0e8cSRob Johnston 
547*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_006: Bad devpath (no NUL term)");
548*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
549*508a0e8cSRob Johnston 	(void) strncpy(ubz.ufbz_devpath, no_nul, MAXPATHLEN);
550*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
551*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
552*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
553*508a0e8cSRob Johnston 	else
554*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
555*508a0e8cSRob Johnston 
556*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
557*508a0e8cSRob Johnston 
558*508a0e8cSRob Johnston 	logmsg("TEST ufm_reportsz_negative_007: Bad devpath (not ascii str)");
559*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
560*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, (char *)not_ascii, MAXPATHLEN);
561*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
562*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
563*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
564*508a0e8cSRob Johnston 	else
565*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
566*508a0e8cSRob Johnston 
567*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
568*508a0e8cSRob Johnston 
569*508a0e8cSRob Johnston 	/*
570*508a0e8cSRob Johnston 	 * Assertion: Specifying a DDI UFM version that is out of range in the
571*508a0e8cSRob Johnston 	 * argument to UFM_IOC_REPORT will fail and set errno to ENOTSUP.
572*508a0e8cSRob Johnston 	 */
573*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_001: Bad DDI UFM version (too low)");
574*508a0e8cSRob Johnston 	urep.ufmr_version = 0;
575*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
576*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
577*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, UFMTEST_DEV, MAXPATHLEN);
578*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
579*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
580*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
581*508a0e8cSRob Johnston 	else
582*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
583*508a0e8cSRob Johnston 
584*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
585*508a0e8cSRob Johnston 
586*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_002: Bad DDI UFM version (too high)");
587*508a0e8cSRob Johnston 	urep.ufmr_version = 999;
588*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
589*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
590*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, UFMTEST_DEV, MAXPATHLEN);
591*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
592*508a0e8cSRob Johnston 	    ENOTSUP) != 0)
593*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
594*508a0e8cSRob Johnston 	else
595*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
596*508a0e8cSRob Johnston 
597*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
598*508a0e8cSRob Johnston 
599*508a0e8cSRob Johnston 	/*
600*508a0e8cSRob Johnston 	 * Assertion: Specifying a bad device pathname in the argument to
601*508a0e8cSRob Johnston 	 * UFM_IOC_REPORT will cause the ioctl to fail, but the driver will
602*508a0e8cSRob Johnston 	 * not hang or panic.
603*508a0e8cSRob Johnston 	 */
604*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_003: Bad devpath (empty)");
605*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
606*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
607*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
608*508a0e8cSRob Johnston 	urep.ufmr_devpath[0] = '\0';
609*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
610*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
611*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
612*508a0e8cSRob Johnston 	else
613*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
614*508a0e8cSRob Johnston 
615*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
616*508a0e8cSRob Johnston 
617*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_004: Bad devpath (not a device)");
618*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
619*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
620*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
621*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, "/usr/bin/ls", MAXPATHLEN);
622*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
623*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
624*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
625*508a0e8cSRob Johnston 	else
626*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
627*508a0e8cSRob Johnston 
628*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
629*508a0e8cSRob Johnston 
630*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_005: Bad devpath (not UFM device)");
631*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
632*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
633*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
634*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, "/dev/stdout", MAXPATHLEN);
635*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
636*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
637*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
638*508a0e8cSRob Johnston 	else
639*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
640*508a0e8cSRob Johnston 
641*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
642*508a0e8cSRob Johnston 
643*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_006: Bad devpath (no NUL term)");
644*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
645*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
646*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
647*508a0e8cSRob Johnston 	(void) strncpy(urep.ufmr_devpath, no_nul, MAXPATHLEN);
648*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
649*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
650*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
651*508a0e8cSRob Johnston 	else
652*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
653*508a0e8cSRob Johnston 
654*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
655*508a0e8cSRob Johnston 
656*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_007: Bad devpath (not ascii str)");
657*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
658*508a0e8cSRob Johnston 	urep.ufmr_bufsz = reportsz;
659*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
660*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, (char *)not_ascii, MAXPATHLEN);
661*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
662*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
663*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
664*508a0e8cSRob Johnston 	else
665*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
666*508a0e8cSRob Johnston 
667*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
668*508a0e8cSRob Johnston 
669*508a0e8cSRob Johnston 	/*
670*508a0e8cSRob Johnston 	 * Assertion: Passing a bufsz that is too small to the UFM_IOC_REPORT
671*508a0e8cSRob Johnston 	 * ioctl will cause the ioctl to fail, but the driver will not hang or
672*508a0e8cSRob Johnston 	 * panic.
673*508a0e8cSRob Johnston 	 */
674*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_008: bad bufsz (too small)");
675*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
676*508a0e8cSRob Johnston 	urep.ufmr_bufsz = 10;
677*508a0e8cSRob Johnston 	urep.ufmr_buf = buf;
678*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, UFMTEST_DEV, MAXPATHLEN);
679*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
680*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
681*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
682*508a0e8cSRob Johnston 	else
683*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
684*508a0e8cSRob Johnston 
685*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
686*508a0e8cSRob Johnston 
687*508a0e8cSRob Johnston 	/*
688*508a0e8cSRob Johnston 	 * Assertion: Passing a bufsz that is too small to the UFM_IOC_REPORT
689*508a0e8cSRob Johnston 	 * ioctl will cause the ioctl to fail, but the driver will not hang or
690*508a0e8cSRob Johnston 	 * panic.
691*508a0e8cSRob Johnston 	 */
692*508a0e8cSRob Johnston 	logmsg("TEST ufm_report_negative_009: bad buf (NULL pointer)");
693*508a0e8cSRob Johnston 	urep.ufmr_version = DDI_UFM_CURRENT_VERSION;
694*508a0e8cSRob Johnston 	urep.ufmr_bufsz = 10;
695*508a0e8cSRob Johnston 	urep.ufmr_buf = NULL;
696*508a0e8cSRob Johnston 	(void) strlcpy(urep.ufmr_devpath, UFMTEST_DEV, MAXPATHLEN);
697*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORT, &urep,
698*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
699*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
700*508a0e8cSRob Johnston 	else
701*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
702*508a0e8cSRob Johnston 
703*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
704*508a0e8cSRob Johnston }
705*508a0e8cSRob Johnston 
706*508a0e8cSRob Johnston /*
707*508a0e8cSRob Johnston  * These are a set of negative test cases to verify the correctness and
708*508a0e8cSRob Johnston  * robustness of the DDI UFM subsystems when a driver UFM callback returns
709*508a0e8cSRob Johnston  * an error.
710*508a0e8cSRob Johnston  *
711*508a0e8cSRob Johnston  * For each callback, we do the following:
712*508a0e8cSRob Johnston  *
713*508a0e8cSRob Johnston  * 1. Toggle the callback failure via a UFMTEST_IOC_TOGGLE_FAILS ioctl
714*508a0e8cSRob Johnston  * 2. Force a ddi_ufm_update() via a UFMTEST_IOC_DO_UPDATE ioctl.  This is
715*508a0e8cSRob Johnston  *    done in order to invalidate any cached firmware data for this device.
716*508a0e8cSRob Johnston  * 3. Call UFM_IOC_REPORTSZ ioctl to force the ufm_cache_fill() codepath to
717*508a0e8cSRob Johnston  *    be executed.
718*508a0e8cSRob Johnston  */
719*508a0e8cSRob Johnston static void
do_negative_callback_tests(struct ufm_test_state * tst_state)720*508a0e8cSRob Johnston do_negative_callback_tests(struct ufm_test_state *tst_state)
721*508a0e8cSRob Johnston {
722*508a0e8cSRob Johnston 	ufm_ioc_getcaps_t ugc = { 0 };
723*508a0e8cSRob Johnston 	ufm_ioc_bufsz_t ubz = { 0 };
724*508a0e8cSRob Johnston 	uint32_t failflags;
725*508a0e8cSRob Johnston 	boolean_t failed;
726*508a0e8cSRob Johnston 
727*508a0e8cSRob Johnston 	/*
728*508a0e8cSRob Johnston 	 * Seed the test driver with a set of valid firmware data
729*508a0e8cSRob Johnston 	 */
730*508a0e8cSRob Johnston 	if (do_setfw(tst_state, &fw_data1) != 0) {
731*508a0e8cSRob Johnston 		logmsg("Failed to seed ufmtest driver with fw data");
732*508a0e8cSRob Johnston 		return;
733*508a0e8cSRob Johnston 	}
734*508a0e8cSRob Johnston 
735*508a0e8cSRob Johnston 	/*
736*508a0e8cSRob Johnston 	 * Assertion: If a driver's ddi_ufm_op_getcaps callback returns a
737*508a0e8cSRob Johnston 	 * failure, the kernel should not hang or panic when servicing a
738*508a0e8cSRob Johnston 	 * UFM_IOC_REPORTSZ ioctl.  Furthermore, the UFM_IOC_REPORTSZ ioctl
739*508a0e8cSRob Johnston 	 * should fail.
740*508a0e8cSRob Johnston 	 */
741*508a0e8cSRob Johnston 	logmsg("TEST ufm_callback_negative_001: ddi_ufm_op_getcaps fails");
742*508a0e8cSRob Johnston 	failed = B_FALSE;
743*508a0e8cSRob Johnston 	failflags = UFMTEST_FAIL_GETCAPS;
744*508a0e8cSRob Johnston 	if (do_toggle_fails(tst_state, failflags) != 0 ||
745*508a0e8cSRob Johnston 	    do_update(tst_state) != 0) {
746*508a0e8cSRob Johnston 		failed = B_TRUE;
747*508a0e8cSRob Johnston 	}
748*508a0e8cSRob Johnston 
749*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
750*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
751*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
752*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
753*508a0e8cSRob Johnston 		failed = B_TRUE;
754*508a0e8cSRob Johnston 
755*508a0e8cSRob Johnston 	if (failed)
756*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
757*508a0e8cSRob Johnston 	else
758*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
759*508a0e8cSRob Johnston 
760*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
761*508a0e8cSRob Johnston 
762*508a0e8cSRob Johnston 	/*
763*508a0e8cSRob Johnston 	 * Assertion: If a driver's ddi_ufm_op_getcaps callback returns a
764*508a0e8cSRob Johnston 	 * failure, the kernel should not hang or panic when servicing a
765*508a0e8cSRob Johnston 	 * UFM_IOC_GETCAPS ioctl for that device.  Furthermore, the
766*508a0e8cSRob Johnston 	 * UFM_IOC_GETCAPS ioctl should fail.
767*508a0e8cSRob Johnston 	 */
768*508a0e8cSRob Johnston 	logmsg("TEST ufm_callback_negative_002: ddi_ufm_op_getcaps fails");
769*508a0e8cSRob Johnston 	failed = B_FALSE;
770*508a0e8cSRob Johnston 	ugc.ufmg_version = DDI_UFM_CURRENT_VERSION;
771*508a0e8cSRob Johnston 	(void) strlcpy(ugc.ufmg_devpath, UFMTEST_DEV, MAXPATHLEN);
772*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_GETCAPS, &ugc,
773*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
774*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
775*508a0e8cSRob Johnston 	else
776*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
777*508a0e8cSRob Johnston 
778*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
779*508a0e8cSRob Johnston 
780*508a0e8cSRob Johnston 	/*
781*508a0e8cSRob Johnston 	 * Assertion: If a driver's ddi_ufm_op_nimages callback returns a
782*508a0e8cSRob Johnston 	 * failure, the kernel should not hang or panic when servicing a
783*508a0e8cSRob Johnston 	 * UFM_IOC_REPORTSZ ioctl.  Furthermore, the UFM_IOC_REPORTSZ ioctl
784*508a0e8cSRob Johnston 	 * should fail.
785*508a0e8cSRob Johnston 	 */
786*508a0e8cSRob Johnston 	logmsg("TEST ufm_callback_negative_003: ddi_ufm_op_nimages fails");
787*508a0e8cSRob Johnston 	failed = B_FALSE;
788*508a0e8cSRob Johnston 	failflags = UFMTEST_FAIL_NIMAGES;
789*508a0e8cSRob Johnston 	if (do_toggle_fails(tst_state, failflags) != 0 ||
790*508a0e8cSRob Johnston 	    do_update(tst_state) != 0) {
791*508a0e8cSRob Johnston 		failed = B_TRUE;
792*508a0e8cSRob Johnston 	}
793*508a0e8cSRob Johnston 
794*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
795*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
796*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
797*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
798*508a0e8cSRob Johnston 		failed = B_TRUE;
799*508a0e8cSRob Johnston 
800*508a0e8cSRob Johnston 	if (failed)
801*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
802*508a0e8cSRob Johnston 	else
803*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
804*508a0e8cSRob Johnston 
805*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
806*508a0e8cSRob Johnston 
807*508a0e8cSRob Johnston 	/*
808*508a0e8cSRob Johnston 	 * Assertion: If a driver's ddi_ufm_op_fill_image callback returns a
809*508a0e8cSRob Johnston 	 * failure, the kernel should not hang or panic when servicing a
810*508a0e8cSRob Johnston 	 * UFM_IOC_REPORTSZ ioctl.  Furthermore, the UFM_IOC_REPORTSZ ioctl
811*508a0e8cSRob Johnston 	 * should fail.
812*508a0e8cSRob Johnston 	 */
813*508a0e8cSRob Johnston 	logmsg("TEST ufm_callback_negative_004: ddi_ufm_op_fill_image fails");
814*508a0e8cSRob Johnston 	failed = B_FALSE;
815*508a0e8cSRob Johnston 	failflags = UFMTEST_FAIL_FILLIMAGE;
816*508a0e8cSRob Johnston 	if (do_toggle_fails(tst_state, failflags) != 0 ||
817*508a0e8cSRob Johnston 	    do_update(tst_state) != 0) {
818*508a0e8cSRob Johnston 		failed = B_TRUE;
819*508a0e8cSRob Johnston 	}
820*508a0e8cSRob Johnston 
821*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
822*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
823*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
824*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
825*508a0e8cSRob Johnston 		failed = B_TRUE;
826*508a0e8cSRob Johnston 
827*508a0e8cSRob Johnston 	if (failed)
828*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
829*508a0e8cSRob Johnston 	else
830*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
831*508a0e8cSRob Johnston 
832*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
833*508a0e8cSRob Johnston 
834*508a0e8cSRob Johnston 	/*
835*508a0e8cSRob Johnston 	 * Assertion: If a driver's ddi_ufm_op_fill_slot callback returns a
836*508a0e8cSRob Johnston 	 * failure, the kernel should not hang or panic when servicing a
837*508a0e8cSRob Johnston 	 * UFM_IOC_REPORTSZ ioctl.  Furthermore, the UFM_IOC_REPORTSZ ioctl
838*508a0e8cSRob Johnston 	 * should fail.
839*508a0e8cSRob Johnston 	 */
840*508a0e8cSRob Johnston 	logmsg("TEST ufm_callback_negative_005: ddi_ufm_op_fill_slot fails");
841*508a0e8cSRob Johnston 	failed = B_FALSE;
842*508a0e8cSRob Johnston 	failflags = UFMTEST_FAIL_FILLSLOT;
843*508a0e8cSRob Johnston 	if (do_toggle_fails(tst_state, failflags) != 0 ||
844*508a0e8cSRob Johnston 	    do_update(tst_state) != 0) {
845*508a0e8cSRob Johnston 		failed = B_TRUE;
846*508a0e8cSRob Johnston 	}
847*508a0e8cSRob Johnston 
848*508a0e8cSRob Johnston 	ubz.ufbz_version = DDI_UFM_CURRENT_VERSION;
849*508a0e8cSRob Johnston 	(void) strlcpy(ubz.ufbz_devpath, UFMTEST_DEV, MAXPATHLEN);
850*508a0e8cSRob Johnston 	if (try_ioctl(tst_state->ufts_ufm_fd, UFM_IOC_REPORTSZ, &ubz,
851*508a0e8cSRob Johnston 	    ERRNO_ANY) != 0)
852*508a0e8cSRob Johnston 		failed = B_TRUE;
853*508a0e8cSRob Johnston 
854*508a0e8cSRob Johnston 	if (failed)
855*508a0e8cSRob Johnston 		tst_state->ufts_n_fails++;
856*508a0e8cSRob Johnston 	else
857*508a0e8cSRob Johnston 		tst_state->ufts_n_passes++;
858*508a0e8cSRob Johnston 
859*508a0e8cSRob Johnston 	tst_state->ufts_n_run++;
860*508a0e8cSRob Johnston 
861*508a0e8cSRob Johnston 	/* Unset the fail flags */
862*508a0e8cSRob Johnston 	failflags = 0;
863*508a0e8cSRob Johnston 	if (do_toggle_fails(tst_state, failflags) != 0)
864*508a0e8cSRob Johnston 		logmsg("Failed to clear fail flags");
865*508a0e8cSRob Johnston }
866*508a0e8cSRob Johnston 
867*508a0e8cSRob Johnston int
main(int argc,char ** argv)868*508a0e8cSRob Johnston main(int argc, char **argv)
869*508a0e8cSRob Johnston {
870*508a0e8cSRob Johnston 	int status = EXIT_FAILURE;
871*508a0e8cSRob Johnston 	struct ufm_test_state tst_state = { 0 };
872*508a0e8cSRob Johnston 
873*508a0e8cSRob Johnston 	pname = argv[0];
874*508a0e8cSRob Johnston 
875*508a0e8cSRob Johnston 	if (do_test_setup(&tst_state) != 0) {
876*508a0e8cSRob Johnston 		logmsg("Test setup failed - exiting");
877*508a0e8cSRob Johnston 		return (status);
878*508a0e8cSRob Johnston 	}
879*508a0e8cSRob Johnston 
880*508a0e8cSRob Johnston 	do_negative_open_tests(&tst_state);
881*508a0e8cSRob Johnston 
882*508a0e8cSRob Johnston 	if (tst_state.ufts_ufmtest_fd > 0) {
883*508a0e8cSRob Johnston 		do_negative_ioctl_tests(&tst_state);
884*508a0e8cSRob Johnston 		do_negative_callback_tests(&tst_state);
885*508a0e8cSRob Johnston 	}
886*508a0e8cSRob Johnston 
887*508a0e8cSRob Johnston 	logmsg("Number of Tests Run: %u", tst_state.ufts_n_run);
888*508a0e8cSRob Johnston 	logmsg("Number of Passes:    %u", tst_state.ufts_n_passes);
889*508a0e8cSRob Johnston 	logmsg("Number of Fails :    %u", tst_state.ufts_n_fails);
890*508a0e8cSRob Johnston 	if (tst_state.ufts_n_fails == 0)
891*508a0e8cSRob Johnston 		status = EXIT_SUCCESS;
892*508a0e8cSRob Johnston 
893*508a0e8cSRob Johnston 	(void) close(tst_state.ufts_ufm_fd);
894*508a0e8cSRob Johnston 	if (tst_state.ufts_ufmtest_fd >= 0)
895*508a0e8cSRob Johnston 		(void) close(tst_state.ufts_ufmtest_fd);
896*508a0e8cSRob Johnston 	return (status);
897*508a0e8cSRob Johnston }
898