]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/ses/destructive.c
Add 'contrib/wireguard-tools/' from commit '7e00bf8773b93a2a3ee28dba2710d2ae443989f1'
[FreeBSD/FreeBSD.git] / tests / sys / ses / destructive.c
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  * $FreeBSD$
26  */
27
28 /* Tests that alter an enclosure's state */
29
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32
33 #include <atf-c.h>
34 #include <fcntl.h>
35 #include <glob.h>
36 #include <regex.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include <cam/scsi/scsi_enc.h>
42
43 #include "common.h"
44
45 // Run a test function on just one ses device
46 static void
47 for_one_ses_dev(ses_cb cb)
48 {
49         glob_t g;
50         int fd, r;
51
52         g.gl_pathc = 0;
53         g.gl_pathv = NULL;
54         g.gl_offs = 0;
55
56         r = glob("/dev/ses*", GLOB_NOCHECK | GLOB_NOSORT, NULL, &g);
57         ATF_REQUIRE_EQ(r, 0);
58         if (g.gl_matchc == 0)
59                 return;
60
61         fd = open(g.gl_pathv[0], O_RDWR);
62         ATF_REQUIRE(fd >= 0);
63         cb(g.gl_pathv[0], fd);
64         close(fd);
65
66         globfree(&g);
67 }
68
69 static bool do_setelmstat(const char *devname __unused, int fd) {
70         encioc_element_t *map;
71         unsigned elm_idx;
72         unsigned nobj;
73         int r;
74         elm_type_t last_elm_type = -1;
75
76         r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
77         ATF_REQUIRE_EQ(r, 0);
78
79         map = calloc(nobj, sizeof(encioc_element_t));
80         ATF_REQUIRE(map != NULL);
81         r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
82
83         /* Set the IDENT bit for every disk slot */
84         for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
85                 encioc_elm_status_t elmstat;
86                 struct ses_ctrl_dev_slot *cslot;
87
88                 if (last_elm_type != map[elm_idx].elm_type) {
89                         /* skip overall elements */
90                         last_elm_type = map[elm_idx].elm_type;
91                         continue;
92                 }
93                 elmstat.elm_idx = elm_idx;
94                 if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
95                     map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
96                 {
97                         r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
98                         ATF_REQUIRE_EQ(r, 0);
99
100                         cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
101
102                         ses_ctrl_common_set_select(&cslot->common, 1);
103                         ses_ctrl_dev_slot_set_rqst_ident(cslot, 1);
104                         r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
105                         ATF_REQUIRE_EQ(r, 0);
106                 }
107         }
108
109         /* Check the IDENT bit for every disk slot */
110         last_elm_type = -1;
111         for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
112                 encioc_elm_status_t elmstat;
113                 struct ses_status_dev_slot *sslot;
114
115                 if (last_elm_type != map[elm_idx].elm_type) {
116                         /* skip overall elements */
117                         last_elm_type = map[elm_idx].elm_type;
118                         continue;
119                 }
120                 elmstat.elm_idx = elm_idx;
121                 if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
122                     map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
123                 {
124                         int i;
125
126                         r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
127                         ATF_REQUIRE_EQ(r, 0);
128
129                         sslot = (struct ses_status_dev_slot*)&elmstat.cstat[0];
130
131                         for (i = 0; i < 10; i++) {
132                                 r = ioctl(fd, ENCIOC_GETELMSTAT,
133                                     (caddr_t)&elmstat);
134                                 ATF_REQUIRE_EQ(r, 0);
135                                 if (0 == ses_status_dev_slot_get_ident(sslot)) {
136                                         /* Needs more time to take effect */
137                                         usleep(100000);
138                                 }
139                         }
140                         ATF_CHECK(ses_status_dev_slot_get_ident(sslot) != 0);
141
142                 }
143         }
144
145         free(map);
146         return (true);
147 }
148
149 /*
150  * sg_ses doesn't provide "dump and restore" functionality.  The closest is to
151  * dump status page 2, then manually edit the file to set every individual
152  * element select bit, then load the entire file.  But that is much too hard.
153  * Instead, we'll just clear every ident bit.
154  */
155 static bool
156 do_setelmstat_cleanup(const char *devname __unused, int fd __unused) {
157         encioc_element_t *map;
158         unsigned elm_idx;
159         unsigned nobj;
160         int r;
161         elm_type_t last_elm_type = -1;
162
163         r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
164         ATF_REQUIRE_EQ(r, 0);
165
166         map = calloc(nobj, sizeof(encioc_element_t));
167         ATF_REQUIRE(map != NULL);
168         r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
169
170         /* Clear the IDENT bit for every disk slot */
171         for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
172                 encioc_elm_status_t elmstat;
173                 struct ses_ctrl_dev_slot *cslot;
174
175                 if (last_elm_type != map[elm_idx].elm_type) {
176                         /* skip overall elements */
177                         last_elm_type = map[elm_idx].elm_type;
178                         continue;
179                 }
180                 elmstat.elm_idx = elm_idx;
181                 if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
182                     map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
183                 {
184                         cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
185
186                         ses_ctrl_common_set_select(&cslot->common, 1);
187                         ses_ctrl_dev_slot_set_rqst_ident(cslot, 0);
188                         r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
189                 }
190         }
191
192         return(true);
193 }
194
195
196 ATF_TC_WITH_CLEANUP(setelmstat);
197 ATF_TC_HEAD(setelmstat, tc)
198 {
199         atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETELMSTAT");
200         atf_tc_set_md_var(tc, "require.user", "root");
201 }
202 ATF_TC_BODY(setelmstat, tc)
203 {
204         if (!has_ses())
205                 atf_tc_skip("No ses devices found");
206
207         for_one_ses_dev(do_setelmstat);
208 }
209 ATF_TC_CLEANUP(setelmstat, tc)
210 {
211         if (!has_ses())
212                 return;
213
214         for_one_ses_dev(do_setelmstat_cleanup);
215 }
216
217
218 static bool do_setencstat(const char *devname __unused, int fd) {
219         unsigned char encstat;
220         int r, i;
221         bool worked = false;
222
223         /*
224          * SES provides no way to read the current setting of the enclosure
225          * control page common status bits.  So we'll blindly set CRIT.
226          */
227         encstat = 1 << SES_CTRL_PAGE_CRIT_SHIFT;
228         r = ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
229         ATF_REQUIRE_EQ(r, 0);
230
231         /* Check that the status has changed */
232         for (i = 0; i < 10; i++) {
233                 r = ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &encstat);
234                 ATF_REQUIRE_EQ(r, 0);
235                 if (encstat & SES_CTRL_PAGE_CRIT_MASK) {
236                         worked = true;
237                         break;
238                 }
239                 usleep(100000);
240         }
241         if (!worked) {
242                 /* Some enclosures don't support setting the enclosure status */
243                 return (false);
244         } else
245                 return (true);
246 }
247
248 static bool do_setencstat_cleanup(const char *devname __unused, int fd) {
249         unsigned char encstat;
250
251         /*
252          * SES provides no way to read the current setting of the enclosure
253          * control page common status bits.  So we don't know what they were
254          * set to before the test.  We'll blindly clear all bits.
255          */
256         encstat = 0;
257         ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
258         return (true);
259 }
260
261 ATF_TC_WITH_CLEANUP(setencstat);
262 ATF_TC_HEAD(setencstat, tc)
263 {
264         atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETENCSTAT");
265         atf_tc_set_md_var(tc, "require.user", "root");
266 }
267 ATF_TC_BODY(setencstat, tc)
268 {
269         if (!has_ses())
270                 atf_tc_skip("No ses devices found");
271
272         for_each_ses_dev(do_setencstat, O_RDWR);
273 }
274 ATF_TC_CLEANUP(setencstat, tc)
275 {
276         for_each_ses_dev(do_setencstat_cleanup, O_RDWR);
277 }
278
279 ATF_TP_ADD_TCS(tp)
280 {
281
282         /*
283          * Untested ioctls:
284          *
285          * * ENCIOC_INIT because SES doesn't need it and I don't have any
286          *   SAF-TE devices.
287          *
288          * * ENCIOC_SETSTRING because it's seriously unsafe!  It's normally
289          *   used for stuff like firmware updates
290          */
291         ATF_TP_ADD_TC(tp, setelmstat);
292         ATF_TP_ADD_TC(tp, setencstat);
293         // TODO ENCIOC_SETELMSTAT
294
295         return (atf_no_error());
296 }