xref: /freebsd/tests/sys/ses/destructive.c (revision 2c449a4c5a338d2dd39a1949524e57c06ce7eff6)
1eea7c615SAlan Somers /*-
2eea7c615SAlan Somers  * Copyright (C) 2021 Axcient, Inc. All rights reserved.
3eea7c615SAlan Somers  *
4eea7c615SAlan Somers  * Redistribution and use in source and binary forms, with or without
5eea7c615SAlan Somers  * modification, are permitted provided that the following conditions
6eea7c615SAlan Somers  * are met:
7eea7c615SAlan Somers  * 1. Redistributions of source code must retain the above copyright
8eea7c615SAlan Somers  *    notice, this list of conditions and the following disclaimer.
9eea7c615SAlan Somers  * 2. Redistributions in binary form must reproduce the above copyright
10eea7c615SAlan Somers  *    notice, this list of conditions and the following disclaimer in the
11eea7c615SAlan Somers  *    documentation and/or other materials provided with the distribution.
12eea7c615SAlan Somers  *
13eea7c615SAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14eea7c615SAlan Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15eea7c615SAlan Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16eea7c615SAlan Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17eea7c615SAlan Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18eea7c615SAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19eea7c615SAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20eea7c615SAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21eea7c615SAlan Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22eea7c615SAlan Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23eea7c615SAlan Somers  * SUCH DAMAGE.
24eea7c615SAlan Somers  *
25eea7c615SAlan Somers  * $FreeBSD$
26eea7c615SAlan Somers  */
27eea7c615SAlan Somers 
28eea7c615SAlan Somers /* Tests that alter an enclosure's state */
29eea7c615SAlan Somers 
30eea7c615SAlan Somers #include <sys/types.h>
31eea7c615SAlan Somers #include <sys/ioctl.h>
32eea7c615SAlan Somers 
33eea7c615SAlan Somers #include <atf-c.h>
34eea7c615SAlan Somers #include <fcntl.h>
35eea7c615SAlan Somers #include <glob.h>
36eea7c615SAlan Somers #include <regex.h>
37eea7c615SAlan Somers #include <stdint.h>
38eea7c615SAlan Somers #include <stdio.h>
39eea7c615SAlan Somers #include <stdlib.h>
40eea7c615SAlan Somers 
41eea7c615SAlan Somers #include <cam/scsi/scsi_enc.h>
42eea7c615SAlan Somers 
43eea7c615SAlan Somers #include "common.h"
44eea7c615SAlan Somers 
45eea7c615SAlan Somers // Run a test function on just one ses device
46eea7c615SAlan Somers static void
47eea7c615SAlan Somers for_one_ses_dev(ses_cb cb)
48eea7c615SAlan Somers {
49eea7c615SAlan Somers 	glob_t g;
50eea7c615SAlan Somers 	int fd, r;
51eea7c615SAlan Somers 
52eea7c615SAlan Somers 	g.gl_pathc = 0;
53eea7c615SAlan Somers 	g.gl_pathv = NULL;
54eea7c615SAlan Somers 	g.gl_offs = 0;
55eea7c615SAlan Somers 
56*2c449a4cSLi-Wen Hsu 	r = glob("/dev/ses*", GLOB_NOCHECK | GLOB_NOSORT, NULL, &g);
57eea7c615SAlan Somers 	ATF_REQUIRE_EQ(r, 0);
58*2c449a4cSLi-Wen Hsu 	if (g.gl_matchc == 0)
59*2c449a4cSLi-Wen Hsu 		return;
60eea7c615SAlan Somers 
61eea7c615SAlan Somers 	fd = open(g.gl_pathv[0], O_RDWR);
62eea7c615SAlan Somers 	ATF_REQUIRE(fd >= 0);
63eea7c615SAlan Somers 	cb(g.gl_pathv[0], fd);
64eea7c615SAlan Somers 	close(fd);
65eea7c615SAlan Somers 
66eea7c615SAlan Somers 	globfree(&g);
67eea7c615SAlan Somers }
68eea7c615SAlan Somers 
69eea7c615SAlan Somers static bool do_setelmstat(const char *devname __unused, int fd) {
70eea7c615SAlan Somers 	encioc_element_t *map;
71eea7c615SAlan Somers 	unsigned elm_idx;
72eea7c615SAlan Somers 	unsigned nobj;
73eea7c615SAlan Somers 	int r;
74eea7c615SAlan Somers 	elm_type_t last_elm_type = -1;
75eea7c615SAlan Somers 
76eea7c615SAlan Somers 	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
77eea7c615SAlan Somers 	ATF_REQUIRE_EQ(r, 0);
78eea7c615SAlan Somers 
79eea7c615SAlan Somers 	map = calloc(nobj, sizeof(encioc_element_t));
80eea7c615SAlan Somers 	ATF_REQUIRE(map != NULL);
81eea7c615SAlan Somers 	r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
82eea7c615SAlan Somers 
83eea7c615SAlan Somers 	/* Set the IDENT bit for every disk slot */
84eea7c615SAlan Somers 	for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
85eea7c615SAlan Somers 		encioc_elm_status_t elmstat;
86eea7c615SAlan Somers 		struct ses_ctrl_dev_slot *cslot;
87eea7c615SAlan Somers 
88eea7c615SAlan Somers 		if (last_elm_type != map[elm_idx].elm_type) {
89eea7c615SAlan Somers 			/* skip overall elements */
90eea7c615SAlan Somers 			last_elm_type = map[elm_idx].elm_type;
91eea7c615SAlan Somers 			continue;
92eea7c615SAlan Somers 		}
93eea7c615SAlan Somers 		elmstat.elm_idx = elm_idx;
94eea7c615SAlan Somers 		if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
95eea7c615SAlan Somers 		    map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
96eea7c615SAlan Somers 		{
97eea7c615SAlan Somers 			r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
98eea7c615SAlan Somers 			ATF_REQUIRE_EQ(r, 0);
99eea7c615SAlan Somers 
100eea7c615SAlan Somers 			cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
101eea7c615SAlan Somers 
102eea7c615SAlan Somers 			ses_ctrl_common_set_select(&cslot->common, 1);
103eea7c615SAlan Somers 			ses_ctrl_dev_slot_set_rqst_ident(cslot, 1);
104eea7c615SAlan Somers 			r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
105eea7c615SAlan Somers 			ATF_REQUIRE_EQ(r, 0);
106eea7c615SAlan Somers 		}
107eea7c615SAlan Somers 	}
108eea7c615SAlan Somers 
109eea7c615SAlan Somers 	/* Check the IDENT bit for every disk slot */
110eea7c615SAlan Somers 	last_elm_type = -1;
111eea7c615SAlan Somers 	for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
112eea7c615SAlan Somers 		encioc_elm_status_t elmstat;
113eea7c615SAlan Somers 		struct ses_status_dev_slot *sslot;
114eea7c615SAlan Somers 
115eea7c615SAlan Somers 		if (last_elm_type != map[elm_idx].elm_type) {
116eea7c615SAlan Somers 			/* skip overall elements */
117eea7c615SAlan Somers 			last_elm_type = map[elm_idx].elm_type;
118eea7c615SAlan Somers 			continue;
119eea7c615SAlan Somers 		}
120eea7c615SAlan Somers 		elmstat.elm_idx = elm_idx;
121eea7c615SAlan Somers 		if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
122eea7c615SAlan Somers 		    map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
123eea7c615SAlan Somers 		{
124eea7c615SAlan Somers 			int i;
125eea7c615SAlan Somers 
126eea7c615SAlan Somers 			r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
127eea7c615SAlan Somers 			ATF_REQUIRE_EQ(r, 0);
128eea7c615SAlan Somers 
129eea7c615SAlan Somers 			sslot = (struct ses_status_dev_slot*)&elmstat.cstat[0];
130eea7c615SAlan Somers 
131eea7c615SAlan Somers 			for (i = 0; i < 10; i++) {
132eea7c615SAlan Somers 				r = ioctl(fd, ENCIOC_GETELMSTAT,
133eea7c615SAlan Somers 				    (caddr_t)&elmstat);
134eea7c615SAlan Somers 				ATF_REQUIRE_EQ(r, 0);
135eea7c615SAlan Somers 				if (0 == ses_status_dev_slot_get_ident(sslot)) {
136eea7c615SAlan Somers 					/* Needs more time to take effect */
137eea7c615SAlan Somers 					usleep(100000);
138eea7c615SAlan Somers 				}
139eea7c615SAlan Somers 			}
140eea7c615SAlan Somers 			ATF_CHECK(ses_status_dev_slot_get_ident(sslot) != 0);
141eea7c615SAlan Somers 
142eea7c615SAlan Somers 		}
143eea7c615SAlan Somers 	}
144eea7c615SAlan Somers 
145eea7c615SAlan Somers 	free(map);
146eea7c615SAlan Somers 	return (true);
147eea7c615SAlan Somers }
148eea7c615SAlan Somers 
149eea7c615SAlan Somers /*
150eea7c615SAlan Somers  * sg_ses doesn't provide "dump and restore" functionality.  The closest is to
151eea7c615SAlan Somers  * dump status page 2, then manually edit the file to set every individual
152eea7c615SAlan Somers  * element select bit, then load the entire file.  But that is much too hard.
153eea7c615SAlan Somers  * Instead, we'll just clear every ident bit.
154eea7c615SAlan Somers  */
155eea7c615SAlan Somers static bool
156eea7c615SAlan Somers do_setelmstat_cleanup(const char *devname __unused, int fd __unused) {
157eea7c615SAlan Somers 	encioc_element_t *map;
158eea7c615SAlan Somers 	unsigned elm_idx;
159eea7c615SAlan Somers 	unsigned nobj;
160eea7c615SAlan Somers 	int r;
161eea7c615SAlan Somers 	elm_type_t last_elm_type = -1;
162eea7c615SAlan Somers 
163eea7c615SAlan Somers 	r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
164eea7c615SAlan Somers 	ATF_REQUIRE_EQ(r, 0);
165eea7c615SAlan Somers 
166eea7c615SAlan Somers 	map = calloc(nobj, sizeof(encioc_element_t));
167eea7c615SAlan Somers 	ATF_REQUIRE(map != NULL);
168eea7c615SAlan Somers 	r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
169eea7c615SAlan Somers 
170eea7c615SAlan Somers 	/* Clear the IDENT bit for every disk slot */
171eea7c615SAlan Somers 	for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
172eea7c615SAlan Somers 		encioc_elm_status_t elmstat;
173eea7c615SAlan Somers 		struct ses_ctrl_dev_slot *cslot;
174eea7c615SAlan Somers 
175eea7c615SAlan Somers 		if (last_elm_type != map[elm_idx].elm_type) {
176eea7c615SAlan Somers 			/* skip overall elements */
177eea7c615SAlan Somers 			last_elm_type = map[elm_idx].elm_type;
178eea7c615SAlan Somers 			continue;
179eea7c615SAlan Somers 		}
180eea7c615SAlan Somers 		elmstat.elm_idx = elm_idx;
181eea7c615SAlan Somers 		if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
182eea7c615SAlan Somers 		    map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
183eea7c615SAlan Somers 		{
184eea7c615SAlan Somers 			cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
185eea7c615SAlan Somers 
186eea7c615SAlan Somers 			ses_ctrl_common_set_select(&cslot->common, 1);
187eea7c615SAlan Somers 			ses_ctrl_dev_slot_set_rqst_ident(cslot, 0);
188eea7c615SAlan Somers 			r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
189eea7c615SAlan Somers 		}
190eea7c615SAlan Somers 	}
191eea7c615SAlan Somers 
192eea7c615SAlan Somers 	return(true);
193eea7c615SAlan Somers }
194eea7c615SAlan Somers 
195eea7c615SAlan Somers 
196eea7c615SAlan Somers ATF_TC_WITH_CLEANUP(setelmstat);
197eea7c615SAlan Somers ATF_TC_HEAD(setelmstat, tc)
198eea7c615SAlan Somers {
199eea7c615SAlan Somers 	atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETELMSTAT");
200eea7c615SAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
201eea7c615SAlan Somers }
202eea7c615SAlan Somers ATF_TC_BODY(setelmstat, tc)
203eea7c615SAlan Somers {
204*2c449a4cSLi-Wen Hsu 	if (!has_ses())
205*2c449a4cSLi-Wen Hsu 		atf_tc_skip("No ses devices found");
206*2c449a4cSLi-Wen Hsu 
207eea7c615SAlan Somers 	for_one_ses_dev(do_setelmstat);
208eea7c615SAlan Somers }
209eea7c615SAlan Somers ATF_TC_CLEANUP(setelmstat, tc)
210eea7c615SAlan Somers {
211*2c449a4cSLi-Wen Hsu 	if (!has_ses())
212*2c449a4cSLi-Wen Hsu 		return;
213*2c449a4cSLi-Wen Hsu 
214eea7c615SAlan Somers 	for_one_ses_dev(do_setelmstat_cleanup);
215eea7c615SAlan Somers }
216eea7c615SAlan Somers 
217eea7c615SAlan Somers 
218eea7c615SAlan Somers static bool do_setencstat(const char *devname __unused, int fd) {
219eea7c615SAlan Somers 	unsigned char encstat;
220eea7c615SAlan Somers 	int r, i;
221eea7c615SAlan Somers 	bool worked = false;
222eea7c615SAlan Somers 
223eea7c615SAlan Somers 	/*
224eea7c615SAlan Somers 	 * SES provides no way to read the current setting of the enclosure
225eea7c615SAlan Somers 	 * control page common status bits.  So we'll blindly set CRIT.
226eea7c615SAlan Somers 	 */
227eea7c615SAlan Somers 	encstat = 1 << SES_CTRL_PAGE_CRIT_SHIFT;
228eea7c615SAlan Somers 	r = ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
229eea7c615SAlan Somers 	ATF_REQUIRE_EQ(r, 0);
230eea7c615SAlan Somers 
231eea7c615SAlan Somers 	/* Check that the status has changed */
232eea7c615SAlan Somers 	for (i = 0; i < 10; i++) {
233eea7c615SAlan Somers 		r = ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &encstat);
234eea7c615SAlan Somers 		ATF_REQUIRE_EQ(r, 0);
235eea7c615SAlan Somers 		if (encstat & SES_CTRL_PAGE_CRIT_MASK) {
236eea7c615SAlan Somers 			worked = true;
237eea7c615SAlan Somers 			break;
238eea7c615SAlan Somers 		}
239eea7c615SAlan Somers 		usleep(100000);
240eea7c615SAlan Somers 	}
241eea7c615SAlan Somers 	if (!worked) {
242eea7c615SAlan Somers 		/* Some enclosures don't support setting the enclosure status */
243eea7c615SAlan Somers 		return (false);
244eea7c615SAlan Somers 	} else
245eea7c615SAlan Somers 		return (true);
246eea7c615SAlan Somers }
247eea7c615SAlan Somers 
248eea7c615SAlan Somers static bool do_setencstat_cleanup(const char *devname __unused, int fd) {
249eea7c615SAlan Somers 	unsigned char encstat;
250eea7c615SAlan Somers 
251eea7c615SAlan Somers 	/*
252eea7c615SAlan Somers 	 * SES provides no way to read the current setting of the enclosure
253eea7c615SAlan Somers 	 * control page common status bits.  So we don't know what they were
254eea7c615SAlan Somers 	 * set to before the test.  We'll blindly clear all bits.
255eea7c615SAlan Somers 	 */
256eea7c615SAlan Somers 	encstat = 0;
257eea7c615SAlan Somers 	ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
258eea7c615SAlan Somers 	return (true);
259eea7c615SAlan Somers }
260eea7c615SAlan Somers 
261eea7c615SAlan Somers ATF_TC_WITH_CLEANUP(setencstat);
262eea7c615SAlan Somers ATF_TC_HEAD(setencstat, tc)
263eea7c615SAlan Somers {
264eea7c615SAlan Somers 	atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETENCSTAT");
265eea7c615SAlan Somers 	atf_tc_set_md_var(tc, "require.user", "root");
266eea7c615SAlan Somers }
267eea7c615SAlan Somers ATF_TC_BODY(setencstat, tc)
268eea7c615SAlan Somers {
269*2c449a4cSLi-Wen Hsu 	if (!has_ses())
270*2c449a4cSLi-Wen Hsu 		atf_tc_skip("No ses devices found");
271*2c449a4cSLi-Wen Hsu 
272eea7c615SAlan Somers 	for_each_ses_dev(do_setencstat, O_RDWR);
273eea7c615SAlan Somers }
274eea7c615SAlan Somers ATF_TC_CLEANUP(setencstat, tc)
275eea7c615SAlan Somers {
276eea7c615SAlan Somers 	for_each_ses_dev(do_setencstat_cleanup, O_RDWR);
277eea7c615SAlan Somers }
278eea7c615SAlan Somers 
279eea7c615SAlan Somers ATF_TP_ADD_TCS(tp)
280eea7c615SAlan Somers {
281eea7c615SAlan Somers 
282eea7c615SAlan Somers 	/*
283eea7c615SAlan Somers 	 * Untested ioctls:
284eea7c615SAlan Somers 	 *
285eea7c615SAlan Somers 	 * * ENCIOC_INIT because SES doesn't need it and I don't have any
286eea7c615SAlan Somers 	 *   SAF-TE devices.
287eea7c615SAlan Somers 	 *
288eea7c615SAlan Somers 	 * * ENCIOC_SETSTRING because it's seriously unsafe!  It's normally
289eea7c615SAlan Somers 	 *   used for stuff like firmware updates
290eea7c615SAlan Somers 	 */
291eea7c615SAlan Somers 	ATF_TP_ADD_TC(tp, setelmstat);
292eea7c615SAlan Somers 	ATF_TP_ADD_TC(tp, setencstat);
293eea7c615SAlan Somers 	// TODO ENCIOC_SETELMSTAT
294eea7c615SAlan Somers 
295eea7c615SAlan Somers 	return (atf_no_error());
296eea7c615SAlan Somers }
297