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