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