Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/ses/destructive.c
39536 views
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
/* Tests that alter an enclosure's state */
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
43
// Run a test function on just one ses device
44
static void
45
for_one_ses_dev(ses_cb cb)
46
{
47
glob_t g;
48
int fd, r;
49
50
g.gl_pathc = 0;
51
g.gl_pathv = NULL;
52
g.gl_offs = 0;
53
54
r = glob("/dev/ses*", GLOB_NOCHECK | GLOB_NOSORT, NULL, &g);
55
ATF_REQUIRE_EQ(r, 0);
56
if (g.gl_matchc == 0)
57
return;
58
59
fd = open(g.gl_pathv[0], O_RDWR);
60
ATF_REQUIRE(fd >= 0);
61
cb(g.gl_pathv[0], fd);
62
close(fd);
63
64
globfree(&g);
65
}
66
67
static bool
68
do_setelmstat(const char *devname __unused, int fd)
69
{
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
ses_status_to_ctrl(map[elm_idx].elm_type,
100
&elmstat.cstat[0]);
101
102
cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
103
104
ses_ctrl_common_set_select(&cslot->common, 1);
105
ses_ctrl_dev_slot_set_rqst_ident(cslot, 1);
106
r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
107
ATF_REQUIRE_EQ(r, 0);
108
}
109
}
110
111
/* Check the IDENT bit for every disk slot */
112
last_elm_type = -1;
113
for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
114
encioc_elm_status_t elmstat;
115
struct ses_status_dev_slot *sslot =
116
(struct ses_status_dev_slot*)&elmstat.cstat[0];
117
118
if (last_elm_type != map[elm_idx].elm_type) {
119
/* skip overall elements */
120
last_elm_type = map[elm_idx].elm_type;
121
continue;
122
}
123
elmstat.elm_idx = elm_idx;
124
if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
125
map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
126
{
127
int i;
128
129
for (i = 0; i < 10; i++) {
130
r = ioctl(fd, ENCIOC_GETELMSTAT,
131
(caddr_t)&elmstat);
132
ATF_REQUIRE_EQ(r, 0);
133
if (0 == ses_status_dev_slot_get_ident(sslot)) {
134
/* Needs more time to take effect */
135
usleep(100000);
136
}
137
}
138
ATF_CHECK(ses_status_dev_slot_get_ident(sslot) != 0);
139
140
}
141
}
142
143
free(map);
144
return (true);
145
}
146
147
/*
148
* sg_ses doesn't provide "dump and restore" functionality. The closest is to
149
* dump status page 2, then manually edit the file to set every individual
150
* element select bit, then load the entire file. But that is much too hard.
151
* Instead, we'll just clear every ident bit.
152
*/
153
static bool
154
do_setelmstat_cleanup(const char *devname __unused, int fd __unused)
155
{
156
encioc_element_t *map;
157
unsigned elm_idx;
158
unsigned nobj;
159
int r;
160
elm_type_t last_elm_type = -1;
161
162
r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
163
ATF_REQUIRE_EQ(r, 0);
164
165
map = calloc(nobj, sizeof(encioc_element_t));
166
ATF_REQUIRE(map != NULL);
167
r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
168
ATF_REQUIRE_EQ(r, 0);
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
r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
185
ATF_REQUIRE_EQ(r, 0);
186
ses_status_to_ctrl(map[elm_idx].elm_type,
187
&elmstat.cstat[0]);
188
189
cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
190
191
ses_ctrl_common_set_select(&cslot->common, 1);
192
ses_ctrl_dev_slot_set_rqst_ident(cslot, 0);
193
r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
194
ATF_REQUIRE_EQ(r, 0);
195
}
196
}
197
198
return(true);
199
}
200
201
202
ATF_TC_WITH_CLEANUP(setelmstat);
203
ATF_TC_HEAD(setelmstat, tc)
204
{
205
atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETELMSTAT");
206
atf_tc_set_md_var(tc, "require.user", "root");
207
}
208
ATF_TC_BODY(setelmstat, tc)
209
{
210
if (!has_ses())
211
atf_tc_skip("No ses devices found");
212
213
for_one_ses_dev(do_setelmstat);
214
}
215
ATF_TC_CLEANUP(setelmstat, tc)
216
{
217
if (!has_ses())
218
return;
219
220
for_one_ses_dev(do_setelmstat_cleanup);
221
}
222
223
224
static bool
225
do_setencstat(const char *devname __unused, int fd)
226
{
227
unsigned char encstat;
228
int r, i;
229
bool worked = false;
230
231
/*
232
* SES provides no way to read the current setting of the enclosure
233
* control page common status bits. So we'll blindly set CRIT.
234
*/
235
encstat = 1 << SES_CTRL_PAGE_CRIT_SHIFT;
236
r = ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
237
ATF_REQUIRE_EQ(r, 0);
238
239
/* Check that the status has changed */
240
for (i = 0; i < 10; i++) {
241
r = ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &encstat);
242
ATF_REQUIRE_EQ(r, 0);
243
if (encstat & SES_CTRL_PAGE_CRIT_MASK) {
244
worked = true;
245
break;
246
}
247
usleep(100000);
248
}
249
if (!worked) {
250
/* Some enclosures don't support setting the enclosure status */
251
return (false);
252
} else
253
return (true);
254
}
255
256
static bool
257
do_setencstat_cleanup(const char *devname __unused, int fd)
258
{
259
unsigned char encstat;
260
261
/*
262
* SES provides no way to read the current setting of the enclosure
263
* control page common status bits. So we don't know what they were
264
* set to before the test. We'll blindly clear all bits.
265
*/
266
encstat = 0;
267
ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
268
return (true);
269
}
270
271
ATF_TC_WITH_CLEANUP(setencstat);
272
ATF_TC_HEAD(setencstat, tc)
273
{
274
atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETENCSTAT");
275
atf_tc_set_md_var(tc, "require.user", "root");
276
}
277
ATF_TC_BODY(setencstat, tc)
278
{
279
if (!has_ses())
280
atf_tc_skip("No ses devices found");
281
282
for_each_ses_dev(do_setencstat, O_RDWR);
283
}
284
ATF_TC_CLEANUP(setencstat, tc)
285
{
286
for_each_ses_dev(do_setencstat_cleanup, O_RDWR);
287
}
288
289
ATF_TP_ADD_TCS(tp)
290
{
291
292
/*
293
* Untested ioctls:
294
*
295
* * ENCIOC_INIT because SES doesn't need it and I don't have any
296
* SAF-TE devices.
297
*
298
* * ENCIOC_SETSTRING because it's seriously unsafe! It's normally
299
* used for stuff like firmware updates
300
*/
301
ATF_TP_ADD_TC(tp, setelmstat);
302
ATF_TP_ADD_TC(tp, setencstat);
303
304
return (atf_no_error());
305
}
306
307