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