1287473Sbapt/*- 2287473Sbapt * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3287988Sallanjude * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org> 4287988Sallanjude * Copyright (c) 2000 by Matthew Jacob 5287473Sbapt * All rights reserved. 6287473Sbapt * 7287473Sbapt * Redistribution and use in source and binary forms, with or without 8287473Sbapt * modification, are permitted provided that the following conditions 9287473Sbapt * are met: 10287473Sbapt * 1. Redistributions of source code must retain the above copyright 11287473Sbapt * notice, this list of conditions and the following disclaimer 12287473Sbapt * in this position and unchanged. 13287473Sbapt * 2. Redistributions in binary form must reproduce the above copyright 14287473Sbapt * notice, this list of conditions and the following disclaimer in the 15287473Sbapt * documentation and/or other materials provided with the distribution. 16287473Sbapt * 17287473Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18287473Sbapt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19287473Sbapt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20287473Sbapt * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21287473Sbapt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22287473Sbapt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23287473Sbapt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24287473Sbapt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25287473Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26287473Sbapt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27287473Sbapt */ 28287473Sbapt 29287473Sbapt#include <sys/cdefs.h> 30287473Sbapt__FBSDID("$FreeBSD: stable/11/usr.sbin/sesutil/sesutil.c 359198 2020-03-22 01:01:47Z asomers $"); 31287473Sbapt 32321287Sbapt#include <sys/endian.h> 33287473Sbapt#include <sys/param.h> 34287473Sbapt#include <sys/ioctl.h> 35292121Sbapt#include <sys/types.h> 36287473Sbapt 37287473Sbapt#include <err.h> 38287473Sbapt#include <errno.h> 39287473Sbapt#include <fcntl.h> 40287988Sallanjude#include <getopt.h> 41287473Sbapt#include <glob.h> 42287473Sbapt#include <stdbool.h> 43287473Sbapt#include <stddef.h> 44287473Sbapt#include <stdint.h> 45287473Sbapt#include <stdio.h> 46287473Sbapt#include <stdlib.h> 47287473Sbapt#include <string.h> 48287473Sbapt#include <unistd.h> 49321287Sbapt#include <libxo/xo.h> 50287473Sbapt 51287473Sbapt#include <cam/scsi/scsi_enc.h> 52287473Sbapt 53287988Sallanjude#include "eltsub.h" 54287988Sallanjude 55321287Sbapt#define SESUTIL_XO_VERSION "1" 56321287Sbapt 57287988Sallanjudestatic int encstatus(int argc, char **argv); 58287988Sallanjudestatic int fault(int argc, char **argv); 59287473Sbaptstatic int locate(int argc, char **argv); 60287988Sallanjudestatic int objmap(int argc, char **argv); 61287988Sallanjudestatic int sesled(int argc, char **argv, bool fault); 62321287Sbaptstatic void sesutil_print(bool *title, const char *fmt, ...) __printflike(2,3); 63287473Sbapt 64287473Sbaptstatic struct command { 65287473Sbapt const char *name; 66287988Sallanjude const char *param; 67287473Sbapt const char *desc; 68287473Sbapt int (*exec)(int argc, char **argv); 69287473Sbapt} cmds[] = { 70287988Sallanjude { "fault", 71287988Sallanjude "(<disk>|<sesid>|all) (on|off)", 72287988Sallanjude "Change the state of the fault LED associated with a disk", 73287988Sallanjude fault }, 74287988Sallanjude { "locate", 75287988Sallanjude "(<disk>|<sesid>|all) (on|off)", 76287988Sallanjude "Change the state of the locate LED associated with a disk", 77287988Sallanjude locate }, 78287988Sallanjude { "map", "", 79287988Sallanjude "Print a map of the devices managed by the enclosure", objmap } , 80287988Sallanjude { "status", "", "Print the status of the enclosure", 81287988Sallanjude encstatus }, 82287473Sbapt}; 83287473Sbapt 84287473Sbaptstatic const int nbcmds = nitems(cmds); 85287988Sallanjudestatic const char *uflag; 86287473Sbapt 87287473Sbaptstatic void 88287988Sallanjudeusage(FILE *out, const char *subcmd) 89287473Sbapt{ 90287988Sallanjude int i; 91287988Sallanjude 92287988Sallanjude if (subcmd == NULL) { 93287988Sallanjude fprintf(out, "Usage: %s [-u /dev/ses<N>] <command> [options]\n", 94287988Sallanjude getprogname()); 95287988Sallanjude fprintf(out, "Commands supported:\n"); 96287988Sallanjude } 97287988Sallanjude for (i = 0; i < nbcmds; i++) { 98287988Sallanjude if (subcmd != NULL) { 99287988Sallanjude if (strcmp(subcmd, cmds[i].name) == 0) { 100287988Sallanjude fprintf(out, "Usage: %s %s [-u /dev/ses<N>] " 101287988Sallanjude "%s\n\t%s\n", getprogname(), subcmd, 102287988Sallanjude cmds[i].param, cmds[i].desc); 103287988Sallanjude break; 104287988Sallanjude } 105287988Sallanjude continue; 106287988Sallanjude } 107287988Sallanjude fprintf(out, " %-12s%s\n\t\t%s\n\n", cmds[i].name, 108287988Sallanjude cmds[i].param, cmds[i].desc); 109287988Sallanjude } 110287988Sallanjude 111287988Sallanjude exit(EXIT_FAILURE); 112287988Sallanjude} 113287988Sallanjude 114287988Sallanjudestatic void 115344007Smavdo_led(int fd, unsigned int idx, elm_type_t type, bool onoff, bool setfault) 116287988Sallanjude{ 117344007Smav int state = onoff ? 1 : 0; 118287473Sbapt encioc_elm_status_t o; 119344007Smav struct ses_ctrl_dev_slot *slot; 120287473Sbapt 121287473Sbapt o.elm_idx = idx; 122287473Sbapt if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) { 123287473Sbapt close(fd); 124321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 125287473Sbapt } 126344007Smav slot = (struct ses_ctrl_dev_slot *) &o.cstat[0]; 127344007Smav switch (type) { 128344007Smav case ELMTYP_DEVICE: 129344007Smav case ELMTYP_ARRAY_DEV: 130344007Smav ses_ctrl_common_set_select(&slot->common, 1); 131344007Smav if (setfault) 132344007Smav ses_ctrl_dev_slot_set_rqst_fault(slot, state); 133306796Smav else 134344007Smav ses_ctrl_dev_slot_set_rqst_ident(slot, state); 135344007Smav break; 136344007Smav default: 137344007Smav return; 138287988Sallanjude } 139287473Sbapt if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) { 140287473Sbapt close(fd); 141321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_SETELMSTAT"); 142287473Sbapt } 143287473Sbapt} 144287473Sbapt 145287473Sbaptstatic bool 146287473Sbaptdisk_match(const char *devnames, const char *disk, size_t len) 147287473Sbapt{ 148287494Sbapt const char *dname; 149287473Sbapt 150287494Sbapt dname = devnames; 151287494Sbapt while ((dname = strstr(dname, disk)) != NULL) { 152287988Sallanjude if (dname[len] == '\0' || dname[len] == ',') { 153287473Sbapt return (true); 154287988Sallanjude } 155287494Sbapt dname++; 156287473Sbapt } 157287988Sallanjude 158287473Sbapt return (false); 159287473Sbapt} 160287473Sbapt 161287473Sbaptstatic int 162287992Sallanjudesesled(int argc, char **argv, bool setfault) 163287473Sbapt{ 164287473Sbapt encioc_elm_devnames_t objdn; 165287473Sbapt encioc_element_t *objp; 166287473Sbapt glob_t g; 167287988Sallanjude char *disk, *endptr; 168287988Sallanjude size_t len, i, ndisks; 169287988Sallanjude int fd; 170287988Sallanjude unsigned int nobj, j, sesid; 171287988Sallanjude bool all, isses, onoff; 172287473Sbapt 173287988Sallanjude isses = false; 174287988Sallanjude all = false; 175287988Sallanjude onoff = false; 176287988Sallanjude 177287988Sallanjude if (argc != 3) { 178287992Sallanjude usage(stderr, (setfault ? "fault" : "locate")); 179287473Sbapt } 180287473Sbapt 181287988Sallanjude disk = argv[1]; 182287473Sbapt 183287988Sallanjude sesid = strtoul(disk, &endptr, 10); 184287988Sallanjude if (*endptr == '\0') { 185287988Sallanjude endptr = strrchr(uflag, '*'); 186292122Sbapt if (endptr != NULL && *endptr == '*') { 187321287Sbapt xo_warnx("Must specifying a SES device (-u) to use a SES " 188287988Sallanjude "id# to identify a disk"); 189287992Sallanjude usage(stderr, (setfault ? "fault" : "locate")); 190287988Sallanjude } 191287988Sallanjude isses = true; 192287988Sallanjude } 193287988Sallanjude 194287988Sallanjude if (strcmp(argv[2], "on") == 0) { 195287485Sbapt onoff = true; 196287988Sallanjude } else if (strcmp(argv[2], "off") == 0) { 197287485Sbapt onoff = false; 198287473Sbapt } else { 199287992Sallanjude usage(stderr, (setfault ? "fault" : "locate")); 200287473Sbapt } 201287473Sbapt 202287473Sbapt if (strcmp(disk, "all") == 0) { 203287473Sbapt all = true; 204287473Sbapt } 205287473Sbapt len = strlen(disk); 206287473Sbapt 207287473Sbapt /* Get the list of ses devices */ 208287988Sallanjude if (glob((uflag != NULL ? uflag : "/dev/ses[0-9]*"), 0, NULL, &g) == 209287988Sallanjude GLOB_NOMATCH) { 210287473Sbapt globfree(&g); 211321287Sbapt xo_errx(EXIT_FAILURE, "No SES devices found"); 212287473Sbapt } 213287988Sallanjude 214287988Sallanjude ndisks = 0; 215287473Sbapt for (i = 0; i < g.gl_pathc; i++) { 216287473Sbapt /* ensure we only got numbers after ses */ 217287473Sbapt if (strspn(g.gl_pathv[i] + 8, "0123456789") != 218287988Sallanjude strlen(g.gl_pathv[i] + 8)) { 219287473Sbapt continue; 220287988Sallanjude } 221287473Sbapt if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 222287988Sallanjude /* 223287988Sallanjude * Don't treat non-access errors as critical if we are 224287988Sallanjude * accessing all devices 225287988Sallanjude */ 226287988Sallanjude if (errno == EACCES && g.gl_pathc > 1) { 227321287Sbapt xo_err(EXIT_FAILURE, "unable to access SES device"); 228287988Sallanjude } 229321287Sbapt xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 230287988Sallanjude continue; 231287473Sbapt } 232287473Sbapt 233287988Sallanjude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 234287988Sallanjude close(fd); 235321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 236287988Sallanjude } 237287473Sbapt 238287473Sbapt objp = calloc(nobj, sizeof(encioc_element_t)); 239287988Sallanjude if (objp == NULL) { 240287988Sallanjude close(fd); 241321287Sbapt xo_err(EXIT_FAILURE, "calloc()"); 242287988Sallanjude } 243287473Sbapt 244287988Sallanjude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) { 245359198Sasomers free(objp); 246287988Sallanjude close(fd); 247321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 248287988Sallanjude } 249287473Sbapt 250287988Sallanjude if (isses) { 251359198Sasomers if (sesid >= nobj) { 252359198Sasomers free(objp); 253287988Sallanjude close(fd); 254321287Sbapt xo_errx(EXIT_FAILURE, 255287988Sallanjude "Requested SES ID does not exist"); 256287988Sallanjude } 257344007Smav do_led(fd, sesid, objp[sesid].elm_type, onoff, setfault); 258287988Sallanjude ndisks++; 259359198Sasomers free(objp); 260287988Sallanjude close(fd); 261287988Sallanjude break; 262287988Sallanjude } 263287473Sbapt for (j = 0; j < nobj; j++) { 264359198Sasomers const int devnames_size = 128; 265359198Sasomers char devnames[devnames_size]; 266359198Sasomers 267319901Sallanjude if (all) { 268344007Smav do_led(fd, objp[j].elm_idx, objp[j].elm_type, 269344007Smav onoff, setfault); 270319901Sallanjude continue; 271319901Sallanjude } 272287473Sbapt memset(&objdn, 0, sizeof(objdn)); 273359198Sasomers memset(devnames, 0, devnames_size); 274287473Sbapt objdn.elm_idx = objp[j].elm_idx; 275359198Sasomers objdn.elm_names_size = devnames_size; 276359198Sasomers objdn.elm_devnames = devnames; 277287473Sbapt if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 278287988Sallanjude (caddr_t) &objdn) <0) { 279287473Sbapt continue; 280287988Sallanjude } 281287473Sbapt if (objdn.elm_names_len > 0) { 282287473Sbapt if (disk_match(objdn.elm_devnames, disk, len)) { 283344007Smav do_led(fd, objdn.elm_idx, objp[j].elm_type, 284287992Sallanjude onoff, setfault); 285287988Sallanjude ndisks++; 286287473Sbapt break; 287287473Sbapt } 288287473Sbapt } 289287988Sallanjude } 290298382Sbapt free(objp); 291287473Sbapt close(fd); 292287473Sbapt } 293287473Sbapt globfree(&g); 294287988Sallanjude if (ndisks == 0 && all == false) { 295321287Sbapt xo_errx(EXIT_FAILURE, "Count not find the SES id of device '%s'", 296287988Sallanjude disk); 297287988Sallanjude } 298287473Sbapt 299287473Sbapt return (EXIT_SUCCESS); 300287473Sbapt} 301287473Sbapt 302287988Sallanjudestatic int 303287988Sallanjudelocate(int argc, char **argv) 304287473Sbapt{ 305287473Sbapt 306287988Sallanjude return (sesled(argc, argv, false)); 307287473Sbapt} 308287473Sbapt 309287988Sallanjudestatic int 310287988Sallanjudefault(int argc, char **argv) 311287988Sallanjude{ 312287988Sallanjude 313287988Sallanjude return (sesled(argc, argv, true)); 314287988Sallanjude} 315287988Sallanjude 316321287Sbapt#define TEMPERATURE_OFFSET 20 317321287Sbaptstatic void 318321287Sbaptsesutil_print(bool *title, const char *fmt, ...) 319321287Sbapt{ 320321287Sbapt va_list args; 321321287Sbapt 322321287Sbapt if (!*title) { 323321287Sbapt xo_open_container("extra_status"); 324321287Sbapt xo_emit("\t\tExtra status:\n"); 325321287Sbapt *title = true; 326321287Sbapt } 327321287Sbapt va_start(args, fmt); 328321287Sbapt xo_emit_hv(NULL, fmt, args); 329321287Sbapt va_end(args); 330321287Sbapt} 331321287Sbapt 332321287Sbaptstatic void 333321287Sbaptprint_extra_status(int eletype, u_char *cstat) 334321287Sbapt{ 335321287Sbapt bool title = false; 336321287Sbapt 337321287Sbapt if (cstat[0] & 0x40) { 338321287Sbapt sesutil_print(&title, "\t\t-{e:predicted_failure/true} Predicted Failure\n"); 339321287Sbapt } 340321287Sbapt if (cstat[0] & 0x20) { 341321287Sbapt sesutil_print(&title, "\t\t-{e:disabled/true} Disabled\n"); 342321287Sbapt } 343321287Sbapt if (cstat[0] & 0x10) { 344321287Sbapt sesutil_print(&title, "\t\t-{e:swapped/true} Swapped\n"); 345321287Sbapt } 346321287Sbapt switch (eletype) { 347321287Sbapt case ELMTYP_DEVICE: 348321287Sbapt case ELMTYP_ARRAY_DEV: 349321287Sbapt if (cstat[2] & 0x02) { 350321287Sbapt sesutil_print(&title, "\t\t- LED={q:led/locate}\n"); 351321287Sbapt } 352321287Sbapt if (cstat[2] & 0x20) { 353321287Sbapt sesutil_print(&title, "\t\t- LED={q:led/fault}\n"); 354321287Sbapt } 355321287Sbapt break; 356321287Sbapt case ELMTYP_FAN: 357321287Sbapt sesutil_print(&title, "\t\t- Speed: {:speed/%d}{Uw:rpm}\n", 358321287Sbapt (((0x7 & cstat[1]) << 8) + cstat[2]) * 10); 359321287Sbapt break; 360321287Sbapt case ELMTYP_THERM: 361321287Sbapt if (cstat[2]) { 362321287Sbapt sesutil_print(&title, "\t\t- Temperature: {:temperature/%d}{Uw:C}\n", 363321287Sbapt cstat[2] - TEMPERATURE_OFFSET); 364321287Sbapt } else { 365321287Sbapt sesutil_print(&title, "\t\t- Temperature: -{q:temperature/reserved}-\n"); 366321287Sbapt } 367321287Sbapt break; 368321287Sbapt case ELMTYP_VOM: 369321287Sbapt sesutil_print(&title, "\t\t- Voltage: {:voltage/%.2f}{Uw:V}\n", 370321287Sbapt be16dec(cstat + 2) / 100.0); 371321287Sbapt break; 372321287Sbapt } 373321287Sbapt if (title) { 374321287Sbapt xo_close_container("extra_status"); 375321287Sbapt } 376321287Sbapt} 377321287Sbapt 378287988Sallanjudestatic int 379287988Sallanjudeobjmap(int argc, char **argv __unused) 380287988Sallanjude{ 381292262Sbapt encioc_string_t stri; 382287988Sallanjude encioc_elm_devnames_t e_devname; 383287988Sallanjude encioc_elm_status_t e_status; 384287988Sallanjude encioc_elm_desc_t e_desc; 385287988Sallanjude encioc_element_t *e_ptr; 386287988Sallanjude glob_t g; 387287988Sallanjude int fd; 388287988Sallanjude unsigned int j, nobj; 389287988Sallanjude size_t i; 390292262Sbapt char str[32]; 391287988Sallanjude 392287988Sallanjude if (argc != 1) { 393287988Sallanjude usage(stderr, "map"); 394287988Sallanjude } 395287988Sallanjude 396287988Sallanjude /* Get the list of ses devices */ 397287988Sallanjude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 398287988Sallanjude globfree(&g); 399321287Sbapt xo_errx(EXIT_FAILURE, "No SES devices found"); 400287988Sallanjude } 401321287Sbapt xo_set_version(SESUTIL_XO_VERSION); 402321287Sbapt xo_open_container("sesutil"); 403321287Sbapt xo_open_list("enclosures"); 404287988Sallanjude for (i = 0; i < g.gl_pathc; i++) { 405287988Sallanjude /* ensure we only got numbers after ses */ 406287988Sallanjude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 407287988Sallanjude strlen(g.gl_pathv[i] + 8)) { 408287988Sallanjude continue; 409287988Sallanjude } 410287988Sallanjude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 411287988Sallanjude /* 412287988Sallanjude * Don't treat non-access errors as critical if we are 413287988Sallanjude * accessing all devices 414287988Sallanjude */ 415287988Sallanjude if (errno == EACCES && g.gl_pathc > 1) { 416321287Sbapt xo_err(EXIT_FAILURE, "unable to access SES device"); 417287988Sallanjude } 418321287Sbapt xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 419287988Sallanjude continue; 420287988Sallanjude } 421287988Sallanjude 422287988Sallanjude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 423287988Sallanjude close(fd); 424321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 425287988Sallanjude } 426287988Sallanjude 427287988Sallanjude e_ptr = calloc(nobj, sizeof(encioc_element_t)); 428287988Sallanjude if (e_ptr == NULL) { 429287988Sallanjude close(fd); 430321287Sbapt xo_err(EXIT_FAILURE, "calloc()"); 431287988Sallanjude } 432287988Sallanjude 433287988Sallanjude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) e_ptr) < 0) { 434287988Sallanjude close(fd); 435321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 436287988Sallanjude } 437287988Sallanjude 438321287Sbapt xo_open_instance("enclosures"); 439321287Sbapt xo_emit("{t:enc/%s}:\n", g.gl_pathv[i] + 5); 440292262Sbapt stri.bufsiz = sizeof(str); 441292262Sbapt stri.buf = &str[0]; 442292262Sbapt if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0) 443321287Sbapt xo_emit("\tEnclosure Name: {t:name/%s}\n", stri.buf); 444292262Sbapt stri.bufsiz = sizeof(str); 445292262Sbapt stri.buf = &str[0]; 446292262Sbapt if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0) 447321287Sbapt xo_emit("\tEnclosure ID: {t:id/%s}\n", stri.buf); 448292262Sbapt 449321287Sbapt xo_open_list("elements"); 450287988Sallanjude for (j = 0; j < nobj; j++) { 451287988Sallanjude /* Get the status of the element */ 452287988Sallanjude memset(&e_status, 0, sizeof(e_status)); 453287988Sallanjude e_status.elm_idx = e_ptr[j].elm_idx; 454287988Sallanjude if (ioctl(fd, ENCIOC_GETELMSTAT, 455287988Sallanjude (caddr_t) &e_status) < 0) { 456287988Sallanjude close(fd); 457321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 458287988Sallanjude } 459287988Sallanjude /* Get the description of the element */ 460287988Sallanjude memset(&e_desc, 0, sizeof(e_desc)); 461287988Sallanjude e_desc.elm_idx = e_ptr[j].elm_idx; 462287988Sallanjude e_desc.elm_desc_len = UINT16_MAX; 463287988Sallanjude e_desc.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); 464287988Sallanjude if (e_desc.elm_desc_str == NULL) { 465287988Sallanjude close(fd); 466321287Sbapt xo_err(EXIT_FAILURE, "calloc()"); 467287988Sallanjude } 468287988Sallanjude if (ioctl(fd, ENCIOC_GETELMDESC, 469287988Sallanjude (caddr_t) &e_desc) < 0) { 470287988Sallanjude close(fd); 471321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETELMDESC"); 472287988Sallanjude } 473287988Sallanjude /* Get the device name(s) of the element */ 474287988Sallanjude memset(&e_devname, 0, sizeof(e_devname)); 475287988Sallanjude e_devname.elm_idx = e_ptr[j].elm_idx; 476287988Sallanjude e_devname.elm_names_size = 128; 477287988Sallanjude e_devname.elm_devnames = calloc(128, sizeof(char)); 478287988Sallanjude if (e_devname.elm_devnames == NULL) { 479287988Sallanjude close(fd); 480321287Sbapt xo_err(EXIT_FAILURE, "calloc()"); 481287988Sallanjude } 482287988Sallanjude if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 483287988Sallanjude (caddr_t) &e_devname) <0) { 484287988Sallanjude /* We don't care if this fails */ 485287988Sallanjude e_devname.elm_devnames[0] = '\0'; 486287988Sallanjude } 487321287Sbapt xo_open_instance("elements"); 488321287Sbapt xo_emit("\tElement {:id/%u}, Type: {:type/%s}\n", e_ptr[j].elm_idx, 489287988Sallanjude geteltnm(e_ptr[j].elm_type)); 490321287Sbapt xo_emit("\t\tStatus: {:status/%s} ({q:status_code/0x%02x 0x%02x 0x%02x 0x%02x})\n", 491292121Sbapt scode2ascii(e_status.cstat[0]), e_status.cstat[0], 492292121Sbapt e_status.cstat[1], e_status.cstat[2], 493292121Sbapt e_status.cstat[3]); 494287988Sallanjude if (e_desc.elm_desc_len > 0) { 495321287Sbapt xo_emit("\t\tDescription: {:description/%s}\n", 496287988Sallanjude e_desc.elm_desc_str); 497287988Sallanjude } 498287988Sallanjude if (e_devname.elm_names_len > 0) { 499321287Sbapt xo_emit("\t\tDevice Names: {:device_names/%s}\n", 500287988Sallanjude e_devname.elm_devnames); 501287988Sallanjude } 502321287Sbapt print_extra_status(e_ptr[j].elm_type, e_status.cstat); 503321287Sbapt xo_close_instance("elements"); 504287988Sallanjude free(e_devname.elm_devnames); 505287988Sallanjude } 506321287Sbapt xo_close_list("elements"); 507298382Sbapt free(e_ptr); 508287988Sallanjude close(fd); 509287988Sallanjude } 510287988Sallanjude globfree(&g); 511321287Sbapt xo_close_list("enclosures"); 512321287Sbapt xo_close_container("sesutil"); 513321287Sbapt xo_finish(); 514287988Sallanjude 515287988Sallanjude return (EXIT_SUCCESS); 516287988Sallanjude} 517287988Sallanjude 518287988Sallanjudestatic int 519287988Sallanjudeencstatus(int argc, char **argv __unused) 520287988Sallanjude{ 521287988Sallanjude glob_t g; 522287988Sallanjude int fd, status; 523287988Sallanjude size_t i, e; 524287988Sallanjude u_char estat; 525287988Sallanjude 526287988Sallanjude status = 0; 527287988Sallanjude if (argc != 1) { 528287988Sallanjude usage(stderr, "status"); 529287988Sallanjude } 530287988Sallanjude 531287988Sallanjude /* Get the list of ses devices */ 532287988Sallanjude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 533287988Sallanjude globfree(&g); 534321287Sbapt xo_errx(EXIT_FAILURE, "No SES devices found"); 535287988Sallanjude } 536321287Sbapt 537321287Sbapt xo_set_version(SESUTIL_XO_VERSION); 538321287Sbapt xo_open_container("sesutil"); 539321287Sbapt xo_open_list("enclosures"); 540287988Sallanjude for (i = 0; i < g.gl_pathc; i++) { 541287988Sallanjude /* ensure we only got numbers after ses */ 542287988Sallanjude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 543287988Sallanjude strlen(g.gl_pathv[i] + 8)) { 544287988Sallanjude continue; 545287988Sallanjude } 546287988Sallanjude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 547287988Sallanjude /* 548287988Sallanjude * Don't treat non-access errors as critical if we are 549287988Sallanjude * accessing all devices 550287988Sallanjude */ 551287988Sallanjude if (errno == EACCES && g.gl_pathc > 1) { 552321287Sbapt xo_err(EXIT_FAILURE, "unable to access SES device"); 553287988Sallanjude } 554321287Sbapt xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 555287988Sallanjude continue; 556287988Sallanjude } 557287988Sallanjude 558287988Sallanjude if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) { 559321287Sbapt xo_err(EXIT_FAILURE, "ENCIOC_GETENCSTAT"); 560287988Sallanjude close(fd); 561287988Sallanjude } 562287988Sallanjude 563321287Sbapt xo_open_instance("enclosures"); 564321287Sbapt xo_emit("{:enc/%s}: ", g.gl_pathv[i] + 5); 565287988Sallanjude e = 0; 566287988Sallanjude if (estat == 0) { 567287988Sallanjude if (status == 0) { 568287988Sallanjude status = 1; 569287988Sallanjude } 570321287Sbapt xo_emit("{q:status/OK}"); 571287988Sallanjude } else { 572287988Sallanjude if (estat & SES_ENCSTAT_INFO) { 573321287Sbapt xo_emit("{lq:status/INFO}"); 574287988Sallanjude e++; 575287988Sallanjude } 576287988Sallanjude if (estat & SES_ENCSTAT_NONCRITICAL) { 577287988Sallanjude if (e) 578321287Sbapt xo_emit(","); 579321287Sbapt xo_emit("{lq:status/NONCRITICAL}"); 580287988Sallanjude e++; 581287988Sallanjude } 582287988Sallanjude if (estat & SES_ENCSTAT_CRITICAL) { 583287988Sallanjude if (e) 584321287Sbapt xo_emit(","); 585321287Sbapt xo_emit("{lq:status/CRITICAL}"); 586287988Sallanjude e++; 587287988Sallanjude status = -1; 588287988Sallanjude } 589287988Sallanjude if (estat & SES_ENCSTAT_UNRECOV) { 590287988Sallanjude if (e) 591321287Sbapt xo_emit(","); 592321287Sbapt xo_emit("{lq:status/UNRECOV}"); 593287988Sallanjude e++; 594287988Sallanjude status = -1; 595287988Sallanjude } 596287988Sallanjude } 597321287Sbapt xo_close_instance("enclosures"); 598321287Sbapt xo_emit("\n"); 599287988Sallanjude close(fd); 600287988Sallanjude } 601287988Sallanjude globfree(&g); 602287988Sallanjude 603321287Sbapt xo_close_list("enclosures"); 604321287Sbapt xo_close_container("sesutil"); 605321287Sbapt xo_finish(); 606321287Sbapt 607287988Sallanjude if (status == 1) { 608287988Sallanjude return (EXIT_SUCCESS); 609287988Sallanjude } else { 610287988Sallanjude return (EXIT_FAILURE); 611287988Sallanjude } 612287988Sallanjude} 613287988Sallanjude 614287473Sbaptint 615287473Sbaptmain(int argc, char **argv) 616287473Sbapt{ 617287988Sallanjude int i, ch; 618287473Sbapt struct command *cmd = NULL; 619287473Sbapt 620321287Sbapt argc = xo_parse_args(argc, argv); 621321287Sbapt if (argc < 0) 622321287Sbapt exit(1); 623321287Sbapt 624287988Sallanjude uflag = "/dev/ses[0-9]*"; 625287988Sallanjude while ((ch = getopt_long(argc, argv, "u:", NULL, NULL)) != -1) { 626287988Sallanjude switch (ch) { 627287988Sallanjude case 'u': 628287988Sallanjude uflag = optarg; 629287988Sallanjude break; 630287988Sallanjude case '?': 631287988Sallanjude default: 632287988Sallanjude usage(stderr, NULL); 633287988Sallanjude } 634287988Sallanjude } 635287988Sallanjude argc -= optind; 636287988Sallanjude argv += optind; 637287988Sallanjude 638287988Sallanjude if (argc < 1) { 639287473Sbapt warnx("Missing command"); 640287988Sallanjude usage(stderr, NULL); 641287473Sbapt } 642287473Sbapt 643287473Sbapt for (i = 0; i < nbcmds; i++) { 644287988Sallanjude if (strcmp(argv[0], cmds[i].name) == 0) { 645287473Sbapt cmd = &cmds[i]; 646287473Sbapt break; 647287473Sbapt } 648287473Sbapt } 649287473Sbapt 650287473Sbapt if (cmd == NULL) { 651287988Sallanjude warnx("unknown command %s", argv[0]); 652287988Sallanjude usage(stderr, NULL); 653287473Sbapt } 654287473Sbapt 655287473Sbapt return (cmd->exec(argc, argv)); 656287473Sbapt} 657