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