1/*-
2 * Copyright (C) 2021 Axcient, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26/* Basic smoke test of the ioctl interface */
27
28#include <sys/types.h>
29#include <sys/ioctl.h>
30
31#include <atf-c.h>
32#include <fcntl.h>
33#include <glob.h>
34#include <regex.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39#include <cam/scsi/scsi_enc.h>
40
41#include "common.h"
42
43static bool
44do_getelmdesc(const char *devname, int fd)
45{
46	regex_t re;
47	FILE *pipe;
48	char cmd[256];
49	char line[256];
50	char *actual;
51	unsigned nobj;
52	unsigned elm_idx = 0;
53	int r;
54
55	actual = calloc(UINT16_MAX, sizeof(char));
56	ATF_REQUIRE(actual != NULL);
57	r = regcomp(&re, "(Overall|Element [0-9]+) descriptor: ", REG_EXTENDED);
58	ATF_REQUIRE_EQ(r, 0);
59
60	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
61	ATF_REQUIRE_EQ(r, 0);
62
63	snprintf(cmd, sizeof(cmd), "sg_ses -p7 %s", devname);
64	pipe = popen(cmd, "r");
65	ATF_REQUIRE(pipe != NULL);
66	while(NULL != fgets(line, sizeof(line), pipe)) {
67		regmatch_t matches[1];
68		encioc_elm_desc_t e_desc;
69		char *expected;
70		size_t elen;
71
72		if (regexec(&re, line, 1, matches, 0) == REG_NOMATCH) {
73			continue;
74		}
75
76		expected = &line[matches[0].rm_eo];
77		/* Remove trailing newline */
78		elen = strnlen(expected, sizeof(line) - matches[0].rm_eo);
79		expected[elen - 1] = '\0';
80		/*
81		 * Zero the result string.  XXX we wouldn't have to do this if
82		 * the kernel would nul-terminate the result.
83		 */
84		memset(actual, 0, UINT16_MAX);
85		e_desc.elm_idx = elm_idx;
86		e_desc.elm_desc_len = UINT16_MAX;
87		e_desc.elm_desc_str = actual;
88		r = ioctl(fd, ENCIOC_GETELMDESC, (caddr_t) &e_desc);
89		ATF_REQUIRE_EQ(r, 0);
90		if (0 == strcmp("<empty>", expected)) {
91			/* sg_ses replaces "" with "<empty>" */
92			ATF_CHECK_STREQ("", actual);
93		} else
94			ATF_CHECK_STREQ(expected, actual);
95		elm_idx++;
96	}
97
98	r = pclose(pipe);
99	regfree(&re);
100	free(actual);
101	if (r != 0) {
102		/* Probably an SGPIO device */
103
104		return (false);
105	} else {
106		ATF_CHECK_EQ_MSG(nobj, elm_idx,
107				"Did not find the expected number of element "
108				"descriptors in sg_ses's output");
109		return (true);
110	}
111}
112
113ATF_TC(getelmdesc);
114ATF_TC_HEAD(getelmdesc, tc)
115{
116	atf_tc_set_md_var(tc, "descr",
117	    "Compare ENCIOC_GETELMDESC's output to sg3_utils'");
118	atf_tc_set_md_var(tc, "require.user", "root");
119	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
120}
121ATF_TC_BODY(getelmdesc, tc)
122{
123	if (!has_ses())
124		atf_tc_skip("No ses devices found");
125	for_each_ses_dev(do_getelmdesc, O_RDONLY);
126}
127
128static bool
129do_getelmdevnames(const char *devname __unused, int fd)
130{
131	encioc_element_t *map;
132	unsigned nobj;
133	const size_t namesize = 128;
134	int r, status;
135	char *namebuf;
136	unsigned elm_idx;
137
138	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
139	ATF_REQUIRE_EQ(r, 0);
140
141	namebuf = calloc(namesize, sizeof(char));
142	ATF_REQUIRE(namebuf != NULL);
143	map = calloc(nobj, sizeof(encioc_element_t));
144	ATF_REQUIRE(map != NULL);
145	r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
146	ATF_REQUIRE_EQ(r, 0);
147
148	for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
149		/*
150		 * devnames should be present if:
151		 * * The element is of type Device Slot or Array Device Slot
152		 * * It isn't an Overall Element
153		 * * The element's status is not "Not Installed"
154		 */
155		encioc_elm_status_t e_status;
156		encioc_elm_devnames_t elmdn;
157
158		memset(&e_status, 0, sizeof(e_status));
159		e_status.elm_idx = elm_idx;
160		r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&e_status);
161		ATF_REQUIRE_EQ(r, 0);
162
163		memset(&elmdn, 0, sizeof(elmdn));
164		elmdn.elm_idx = elm_idx;
165		elmdn.elm_names_size = namesize;
166		elmdn.elm_devnames = namebuf;
167		namebuf[0] = '\0';
168		r = ioctl(fd, ENCIOC_GETELMDEVNAMES, (caddr_t) &elmdn);
169		status = ses_status_common_get_element_status_code(
170			(struct ses_status_common*)&e_status.cstat[0]);
171		if (status != SES_OBJSTAT_UNSUPPORTED &&
172		    status != SES_OBJSTAT_NOTINSTALLED &&
173		    (map[elm_idx].elm_type == ELMTYP_DEVICE ||
174		     map[elm_idx].elm_type == ELMTYP_ARRAY_DEV))
175		{
176			ATF_CHECK_EQ_MSG(r, 0, "devnames not found.  This could be due to a buggy ses driver, buggy ses controller, dead HDD, or an ATA HDD in a SAS slot");
177		} else {
178			ATF_CHECK(r != 0);
179		}
180
181		if (r == 0) {
182			size_t z = 0;
183			int da = 0, ada = 0, pass = 0, nda = 0, unknown = 0;
184
185			while(elmdn.elm_devnames[z] != '\0') {
186				size_t e;
187				char *s;
188
189				if (elmdn.elm_devnames[z] == ',')
190					z++;	/* Skip the comma */
191				s = elmdn.elm_devnames + z;
192				e = strcspn(s, "0123456789");
193				if (0 == strncmp("da", s, e))
194					da++;
195				else if (0 == strncmp("ada", s, e))
196					ada++;
197				else if (0 == strncmp("pass", s, e))
198					pass++;
199				else if (0 == strncmp("nda", s, e))
200					nda++;
201				else
202					unknown++;
203				z += strcspn(elmdn.elm_devnames + z, ",");
204			}
205			/* There should be one pass dev for each non-pass dev */
206			ATF_CHECK_EQ(pass, da + ada + nda);
207			ATF_CHECK_EQ_MSG(0, unknown,
208			    "Unknown device names %s", elmdn.elm_devnames);
209		}
210	}
211	free(map);
212	free(namebuf);
213
214	return (true);
215}
216
217ATF_TC(getelmdevnames);
218ATF_TC_HEAD(getelmdevnames, tc)
219{
220	atf_tc_set_md_var(tc, "descr",
221	    "Compare ENCIOC_GETELMDEVNAMES's output to sg3_utils'");
222	atf_tc_set_md_var(tc, "require.user", "root");
223	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
224}
225ATF_TC_BODY(getelmdevnames, tc)
226{
227	if (!has_ses())
228		atf_tc_skip("No ses devices found");
229	for_each_ses_dev(do_getelmdevnames, O_RDONLY);
230}
231
232static int
233elm_type_name2int(const char *name)
234{
235	const char *elm_type_names[] = ELM_TYPE_NAMES;
236	int i;
237
238	for (i = 0; i <= ELMTYP_LAST; i++) {
239		/* sg_ses uses different case than ses(4) */
240		if (0 == strcasecmp(name, elm_type_names[i]))
241			return i;
242	}
243	return (-1);
244}
245
246static bool
247do_getelmmap(const char *devname, int fd)
248{
249	encioc_element_t *map;
250	FILE *pipe;
251	char cmd[256];
252	char line[256];
253	unsigned elm_idx = 0;
254	unsigned nobj, subenc_id;
255	int r, elm_type;
256
257	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
258	ATF_REQUIRE_EQ(r, 0);
259
260	map = calloc(nobj, sizeof(encioc_element_t));
261	ATF_REQUIRE(map != NULL);
262	r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
263	ATF_REQUIRE_EQ(r, 0);
264
265	snprintf(cmd, sizeof(cmd), "sg_ses -p1 %s", devname);
266	pipe = popen(cmd, "r");
267	ATF_REQUIRE(pipe != NULL);
268	while(NULL != fgets(line, sizeof(line), pipe)) {
269		char elm_type_name[80];
270		int i, num_elm;
271
272		r = sscanf(line,
273		    "    Element type: %[a-zA-Z0-9_ /], subenclosure id: %d",
274		    elm_type_name, &subenc_id);
275		if (r == 2) {
276			elm_type = elm_type_name2int(elm_type_name);
277			continue;
278		} else {
279			r = sscanf(line,
280			    "    Element type: vendor specific [0x%x], subenclosure id: %d",
281			    &elm_type, &subenc_id);
282			if (r == 2)
283				continue;
284		}
285		r = sscanf(line, "      number of possible elements: %d",
286		    &num_elm);
287		if (r != 1)
288			continue;
289
290		/* Skip the Overall elements */
291		elm_idx++;
292		for (i = 0; i < num_elm; i++, elm_idx++) {
293			ATF_CHECK_EQ(map[elm_idx].elm_idx, elm_idx);
294			ATF_CHECK_EQ(map[elm_idx].elm_subenc_id, subenc_id);
295			ATF_CHECK_EQ((int)map[elm_idx].elm_type, elm_type);
296		}
297	}
298
299	free(map);
300	r = pclose(pipe);
301	if (r != 0) {
302		/* Probably an SGPIO device */
303		return (false);
304	} else {
305		ATF_CHECK_EQ_MSG(nobj, elm_idx,
306				"Did not find the expected number of element "
307				"descriptors in sg_ses's output");
308		return (true);
309	}
310}
311
312ATF_TC(getelmmap);
313ATF_TC_HEAD(getelmmap, tc)
314{
315	atf_tc_set_md_var(tc, "descr",
316	    "Compare ENCIOC_GETELMMAP's output to sg3_utils'");
317	atf_tc_set_md_var(tc, "require.user", "root");
318	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
319}
320ATF_TC_BODY(getelmmap, tc)
321{
322	if (!has_ses())
323		atf_tc_skip("No ses devices found");
324	for_each_ses_dev(do_getelmmap, O_RDONLY);
325}
326
327static bool
328do_getelmstat(const char *devname, int fd)
329{
330	encioc_element_t *map;
331	unsigned elm_idx;
332	unsigned nobj;
333	int r, elm_subidx;
334	elm_type_t last_elm_type = -1;
335
336	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
337	ATF_REQUIRE_EQ(r, 0);
338
339	map = calloc(nobj, sizeof(encioc_element_t));
340	ATF_REQUIRE(map != NULL);
341	r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
342
343	for (elm_idx = 0; elm_idx < nobj; elm_subidx++, elm_idx++) {
344		encioc_elm_status_t e_status;
345		FILE *pipe;
346		char cmd[256];
347		uint32_t status;
348		int pr;
349
350		if (last_elm_type != map[elm_idx].elm_type)
351			elm_subidx = -1;
352		last_elm_type = map[elm_idx].elm_type;
353
354		snprintf(cmd, sizeof(cmd),
355		    "sg_ses -Hp2 --index=_%d,%d --get=0:7:32 %s",
356		    map[elm_idx].elm_type, elm_subidx, devname);
357		pipe = popen(cmd, "r");
358		ATF_REQUIRE(pipe != NULL);
359		r = fscanf(pipe, "0x%x", &status);
360		pr = pclose(pipe);
361		if (pr != 0) {
362			/* Probably an SGPIO device */
363			free(map);
364			return (false);
365		}
366		ATF_REQUIRE_EQ(r, 1);
367
368		memset(&e_status, 0, sizeof(e_status));
369		e_status.elm_idx = map[elm_idx].elm_idx;
370		r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&e_status);
371		ATF_REQUIRE_EQ(r, 0);
372
373		// Compare the common status field
374		ATF_CHECK_EQ(e_status.cstat[0], status >> 24);
375		/*
376		 * Ignore the other fields, because some have values that can
377		 * change frequently (voltage, temperature, etc)
378		 */
379	}
380	free(map);
381
382	return (true);
383}
384
385ATF_TC(getelmstat);
386ATF_TC_HEAD(getelmstat, tc)
387{
388	atf_tc_set_md_var(tc, "descr",
389	    "Compare ENCIOC_GETELMSTAT's output to sg3_utils'");
390	atf_tc_set_md_var(tc, "require.user", "root");
391	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
392}
393ATF_TC_BODY(getelmstat, tc)
394{
395	if (!has_ses())
396		atf_tc_skip("No ses devices found");
397	for_each_ses_dev(do_getelmstat, O_RDONLY);
398}
399
400static bool
401do_getencid(const char *devname, int fd)
402{
403	encioc_string_t stri;
404	FILE *pipe;
405	char cmd[256];
406	char encid[32];
407	char line[256];
408	char sg_encid[32];
409	int r, sg_ses_r;
410
411	snprintf(cmd, sizeof(cmd), "sg_ses -p1 %s", devname);
412	pipe = popen(cmd, "r");
413	ATF_REQUIRE(pipe != NULL);
414	sg_encid[0] = '\0';
415	while(NULL != fgets(line, sizeof(line), pipe)) {
416		const char *f = "      enclosure logical identifier (hex): %s";
417
418		if (1 == fscanf(pipe, f, sg_encid))
419			break;
420	}
421	sg_ses_r = pclose(pipe);
422
423	stri.bufsiz = sizeof(encid);
424	stri.buf = &encid[0];
425	r = ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri);
426	ATF_REQUIRE_EQ(r, 0);
427	if (sg_ses_r == 0) {
428		ATF_REQUIRE(sg_encid[0] != '\0');
429		ATF_CHECK_STREQ(sg_encid, (char*)stri.buf);
430		return (true);
431	} else {
432		/* Probably SGPIO; sg_ses unsupported */
433		return (false);
434	}
435}
436
437ATF_TC(getencid);
438ATF_TC_HEAD(getencid, tc)
439{
440	atf_tc_set_md_var(tc, "descr",
441	    "Compare ENCIOC_GETENCID's output to sg3_utils'");
442	atf_tc_set_md_var(tc, "require.user", "root");
443	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
444}
445ATF_TC_BODY(getencid, tc)
446{
447	if (!has_ses())
448		atf_tc_skip("No ses devices found");
449	for_each_ses_dev(do_getencid, O_RDONLY);
450}
451
452static bool
453do_getencname(const char *devname, int fd)
454{
455	encioc_string_t stri;
456	FILE *pipe;
457	char cmd[256];
458	char encname[32];
459	char line[256];
460	int r;
461
462	snprintf(cmd, sizeof(cmd), "sg_inq -o %s | awk '"
463		"/Vendor identification/ {vi=$NF} "
464		"/Product identification/ {pi=$NF} "
465		"/Product revision level/ {prl=$NF} "
466		"END {printf(vi \" \" pi \" \" prl)}'", devname);
467	pipe = popen(cmd, "r");
468	ATF_REQUIRE(pipe != NULL);
469	ATF_REQUIRE(NULL != fgets(line, sizeof(line), pipe));
470	pclose(pipe);
471
472	stri.bufsiz = sizeof(encname);
473	stri.buf = &encname[0];
474	r = ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri);
475	ATF_REQUIRE_EQ(r, 0);
476	if (strlen(line) < 3) {
477		// Probably an SGPIO device, INQUIRY unsupported
478		return (false);
479	} else {
480		ATF_CHECK_STREQ(line, (char*)stri.buf);
481		return (true);
482	}
483}
484
485ATF_TC(getencname);
486ATF_TC_HEAD(getencname, tc)
487{
488	atf_tc_set_md_var(tc, "descr",
489	    "Compare ENCIOC_GETENCNAME's output to sg3_utils'");
490	atf_tc_set_md_var(tc, "require.user", "root");
491	atf_tc_set_md_var(tc, "require.progs", "sg_inq");
492}
493ATF_TC_BODY(getencname, tc)
494{
495	if (!has_ses())
496		atf_tc_skip("No ses devices found");
497	for_each_ses_dev(do_getencname, O_RDONLY);
498}
499
500static bool
501do_getencstat(const char *devname, int fd)
502{
503	FILE *pipe;
504	char cmd[256];
505	unsigned char e, estat, invop, info, noncrit, crit, unrecov;
506	int r;
507
508	snprintf(cmd, sizeof(cmd), "sg_ses -p2 %s "
509		"| grep 'INVOP='",
510		devname);
511	pipe = popen(cmd, "r");
512	ATF_REQUIRE(pipe != NULL);
513	r = fscanf(pipe,
514	    "  INVOP=%hhu, INFO=%hhu, NON-CRIT=%hhu, CRIT=%hhu, UNRECOV=%hhu",
515	    &invop, &info, &noncrit, &crit, &unrecov);
516	pclose(pipe);
517	if (r != 5) {
518		/* Probably on SGPIO device */
519		return (false);
520	} else {
521		r = ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat);
522		ATF_REQUIRE_EQ(r, 0);
523		/* Exclude the info bit because it changes frequently */
524		e = (invop << 4) | (noncrit << 2) | (crit << 1) | unrecov;
525		ATF_CHECK_EQ(estat & ~0x08, e);
526		return (true);
527	}
528}
529
530ATF_TC(getencstat);
531ATF_TC_HEAD(getencstat, tc)
532{
533	atf_tc_set_md_var(tc, "descr",
534	    "Compare ENCIOC_GETENCSTAT's output to sg3_utils'");
535	atf_tc_set_md_var(tc, "require.user", "root");
536	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
537}
538ATF_TC_BODY(getencstat, tc)
539{
540	if (!has_ses())
541		atf_tc_skip("No ses devices found");
542	for_each_ses_dev(do_getencstat, O_RDONLY);
543}
544
545static bool
546do_getnelm(const char *devname, int fd)
547{
548	FILE *pipe;
549	char cmd[256];
550	char line[256];
551	unsigned nobj, expected = 0;
552	int r, sg_ses_r;
553
554	snprintf(cmd, sizeof(cmd), "sg_ses -p1 %s", devname);
555	pipe = popen(cmd, "r");
556	ATF_REQUIRE(pipe != NULL);
557
558	while(NULL != fgets(line, sizeof(line), pipe)) {
559		unsigned nelm;
560
561		if (1 == fscanf(pipe, "      number of possible elements: %u",
562		    &nelm))
563		{
564			expected += 1 + nelm;	// +1 for the Overall element
565		}
566	}
567	sg_ses_r = pclose(pipe);
568
569	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
570	ATF_REQUIRE_EQ(r, 0);
571	if (sg_ses_r == 0) {
572		ATF_CHECK_EQ(expected, nobj);
573		return (true);
574	} else {
575		/* Probably SGPIO, sg_ses unsupported */
576		return (false);
577	}
578}
579
580ATF_TC(getnelm);
581ATF_TC_HEAD(getnelm, tc)
582{
583	atf_tc_set_md_var(tc, "descr",
584	    "Compare ENCIOC_GETNELM's output to sg3_utils'");
585	atf_tc_set_md_var(tc, "require.user", "root");
586	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
587}
588ATF_TC_BODY(getnelm, tc)
589{
590	if (!has_ses())
591		atf_tc_skip("No ses devices found");
592	for_each_ses_dev(do_getnelm, O_RDONLY);
593}
594
595static bool
596do_getstring(const char *devname, int fd)
597{
598	FILE *pipe;
599	char cmd[256];
600	char *sg_ses_buf, *ses_buf;
601	ssize_t sg_ses_count;
602	encioc_string_t str_in;
603	int r;
604
605	sg_ses_buf = malloc(65535);
606	ATF_REQUIRE(sg_ses_buf != NULL);
607	ses_buf = malloc(65535);
608	ATF_REQUIRE(ses_buf != NULL);
609
610	snprintf(cmd, sizeof(cmd), "sg_ses -p4 -rr %s", devname);
611	pipe = popen(cmd, "r");
612	ATF_REQUIRE(pipe != NULL);
613	sg_ses_count = fread(sg_ses_buf, 1, 65535, pipe);
614	r = pclose(pipe);
615	if (r != 0) {
616		// This SES device does not support the STRINGIN diagnostic page
617		return (false);
618	}
619	ATF_REQUIRE(sg_ses_count > 0);
620
621	str_in.bufsiz = 65535;
622	str_in.buf = ses_buf;
623	r = ioctl(fd, ENCIOC_GETSTRING, (caddr_t) &str_in);
624	ATF_REQUIRE_EQ(r, 0);
625	ATF_CHECK_EQ(sg_ses_count, (ssize_t)str_in.bufsiz);
626	ATF_CHECK_EQ(0, memcmp(sg_ses_buf, ses_buf, str_in.bufsiz));
627
628	free(ses_buf);
629	free(sg_ses_buf);
630
631	return (true);
632}
633
634ATF_TC(getstring);
635ATF_TC_HEAD(getstring, tc)
636{
637	atf_tc_set_md_var(tc, "descr",
638	    "Compare ENCIOC_GETSTRING's output to sg3_utils'");
639	atf_tc_set_md_var(tc, "require.user", "root");
640	atf_tc_set_md_var(tc, "require.progs", "sg_ses");
641}
642ATF_TC_BODY(getstring, tc)
643{
644	if (!has_ses())
645		atf_tc_skip("No ses devices found");
646	atf_tc_expect_fail("Bug 258188 ENCIO_GETSTRING does not set the string's returned size");
647	for_each_ses_dev(do_getstring, O_RDWR);
648}
649
650ATF_TP_ADD_TCS(tp)
651{
652
653	/*
654	 * Untested ioctls:
655	 *
656	 * * ENCIOC_GETTEXT because it was never implemented
657	 *
658	 */
659	ATF_TP_ADD_TC(tp, getelmdesc);
660	ATF_TP_ADD_TC(tp, getelmdevnames);
661	ATF_TP_ADD_TC(tp, getelmmap);
662	ATF_TP_ADD_TC(tp, getelmstat);
663	ATF_TP_ADD_TC(tp, getencid);
664	ATF_TP_ADD_TC(tp, getencname);
665	ATF_TP_ADD_TC(tp, getencstat);
666	ATF_TP_ADD_TC(tp, getnelm);
667	ATF_TP_ADD_TC(tp, getstring);
668
669	return (atf_no_error());
670}
671