1cddcb259SBaptiste Daroussin /*- 2cddcb259SBaptiste Daroussin * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3cddcb259SBaptiste Daroussin * All rights reserved. 4cddcb259SBaptiste Daroussin * 5cddcb259SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 6cddcb259SBaptiste Daroussin * modification, are permitted provided that the following conditions 7cddcb259SBaptiste Daroussin * are met: 8cddcb259SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 9cddcb259SBaptiste Daroussin * notice, this list of conditions and the following disclaimer 10cddcb259SBaptiste Daroussin * in this position and unchanged. 11cddcb259SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 12cddcb259SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 13cddcb259SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 14cddcb259SBaptiste Daroussin * 15cddcb259SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16cddcb259SBaptiste Daroussin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17cddcb259SBaptiste Daroussin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18cddcb259SBaptiste Daroussin * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19cddcb259SBaptiste Daroussin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20cddcb259SBaptiste Daroussin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21cddcb259SBaptiste Daroussin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22cddcb259SBaptiste Daroussin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23cddcb259SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24cddcb259SBaptiste Daroussin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25cddcb259SBaptiste Daroussin */ 26cddcb259SBaptiste Daroussin 27cddcb259SBaptiste Daroussin #include <sys/cdefs.h> 28cddcb259SBaptiste Daroussin __FBSDID("$FreeBSD$"); 29cddcb259SBaptiste Daroussin 30cddcb259SBaptiste Daroussin #include <sys/param.h> 31cddcb259SBaptiste Daroussin #include <sys/ioctl.h> 32cddcb259SBaptiste Daroussin 33cddcb259SBaptiste Daroussin #include <err.h> 34cddcb259SBaptiste Daroussin #include <errno.h> 35cddcb259SBaptiste Daroussin #include <fcntl.h> 36cddcb259SBaptiste Daroussin #include <glob.h> 37cddcb259SBaptiste Daroussin #include <stdbool.h> 38cddcb259SBaptiste Daroussin #include <stddef.h> 39cddcb259SBaptiste Daroussin #include <stdint.h> 40cddcb259SBaptiste Daroussin #include <stdio.h> 41cddcb259SBaptiste Daroussin #include <stdlib.h> 42cddcb259SBaptiste Daroussin #include <string.h> 43cddcb259SBaptiste Daroussin #include <unistd.h> 44cddcb259SBaptiste Daroussin 45cddcb259SBaptiste Daroussin #include <cam/scsi/scsi_all.h> 46cddcb259SBaptiste Daroussin #include <cam/scsi/scsi_enc.h> 47cddcb259SBaptiste Daroussin 48cddcb259SBaptiste Daroussin static int locate(int argc, char **argv); 49cddcb259SBaptiste Daroussin 50cddcb259SBaptiste Daroussin static struct command { 51cddcb259SBaptiste Daroussin const char *name; 52cddcb259SBaptiste Daroussin const char *desc; 53cddcb259SBaptiste Daroussin int (*exec)(int argc, char **argv); 54cddcb259SBaptiste Daroussin } cmds[] = { 55cddcb259SBaptiste Daroussin { "locate", "Change the state of the external LED associated with a" 56cddcb259SBaptiste Daroussin " disk", locate} , 57cddcb259SBaptiste Daroussin }; 58cddcb259SBaptiste Daroussin 59cddcb259SBaptiste Daroussin static const int nbcmds = nitems(cmds); 60cddcb259SBaptiste Daroussin 61cddcb259SBaptiste Daroussin static void 62cddcb259SBaptiste Daroussin do_locate(int fd, unsigned int idx, bool onoff) 63cddcb259SBaptiste Daroussin { 64cddcb259SBaptiste Daroussin encioc_elm_status_t o; 65cddcb259SBaptiste Daroussin 66cddcb259SBaptiste Daroussin o.elm_idx = idx; 67cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) { 68cddcb259SBaptiste Daroussin close(fd); 69cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 70cddcb259SBaptiste Daroussin } 71cddcb259SBaptiste Daroussin o.cstat[0] |= 0x80; 72cddcb259SBaptiste Daroussin if (onoff) 73cddcb259SBaptiste Daroussin o.cstat[2] |= 0x02; 74cddcb259SBaptiste Daroussin else 75cddcb259SBaptiste Daroussin o.cstat[2] &= 0xfd; 76cddcb259SBaptiste Daroussin 77cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) { 78cddcb259SBaptiste Daroussin close(fd); 79cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "ENCIOC_SETELMSTAT"); 80cddcb259SBaptiste Daroussin } 81cddcb259SBaptiste Daroussin } 82cddcb259SBaptiste Daroussin 83cddcb259SBaptiste Daroussin static bool 84cddcb259SBaptiste Daroussin disk_match(const char *devnames, const char *disk, size_t len) 85cddcb259SBaptiste Daroussin { 86cddcb259SBaptiste Daroussin const char *devname; 87cddcb259SBaptiste Daroussin 88cddcb259SBaptiste Daroussin devname = devnames; 89cddcb259SBaptiste Daroussin while ((devname = strstr(devname, disk)) != NULL) { 90cddcb259SBaptiste Daroussin if (devname[len] == '\0' || devname[len] == ',') 91cddcb259SBaptiste Daroussin return (true); 92cddcb259SBaptiste Daroussin devname++; 93cddcb259SBaptiste Daroussin } 94cddcb259SBaptiste Daroussin return (false); 95cddcb259SBaptiste Daroussin } 96cddcb259SBaptiste Daroussin 97cddcb259SBaptiste Daroussin static int 98cddcb259SBaptiste Daroussin locate(int argc, char **argv) 99cddcb259SBaptiste Daroussin { 100cddcb259SBaptiste Daroussin encioc_elm_devnames_t objdn; 101cddcb259SBaptiste Daroussin encioc_element_t *objp; 102cddcb259SBaptiste Daroussin glob_t g; 103cddcb259SBaptiste Daroussin char *disk; 104cddcb259SBaptiste Daroussin size_t len, i; 105cddcb259SBaptiste Daroussin int fd, nobj, j; 106cddcb259SBaptiste Daroussin bool all = false; 107*4569e7cfSBaptiste Daroussin bool onoff; 108cddcb259SBaptiste Daroussin 109cddcb259SBaptiste Daroussin if (argc != 2) { 110cddcb259SBaptiste Daroussin errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]", 111cddcb259SBaptiste Daroussin getprogname()); 112cddcb259SBaptiste Daroussin } 113cddcb259SBaptiste Daroussin 114cddcb259SBaptiste Daroussin disk = argv[0]; 115cddcb259SBaptiste Daroussin 116cddcb259SBaptiste Daroussin if (strcmp(argv[1], "on") == 0) { 117*4569e7cfSBaptiste Daroussin onoff = true; 118cddcb259SBaptiste Daroussin } else if (strcmp(argv[1], "off") == 0) { 119*4569e7cfSBaptiste Daroussin onoff = false; 120cddcb259SBaptiste Daroussin } else { 121cddcb259SBaptiste Daroussin errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]", 122cddcb259SBaptiste Daroussin getprogname()); 123cddcb259SBaptiste Daroussin } 124cddcb259SBaptiste Daroussin 125cddcb259SBaptiste Daroussin if (strcmp(disk, "all") == 0) { 126cddcb259SBaptiste Daroussin all = true; 127cddcb259SBaptiste Daroussin } 128cddcb259SBaptiste Daroussin len = strlen(disk); 129cddcb259SBaptiste Daroussin 130cddcb259SBaptiste Daroussin /* Get the list of ses devices */ 131cddcb259SBaptiste Daroussin if (glob("/dev/ses[0-9]*", 0, NULL, &g) == GLOB_NOMATCH) { 132cddcb259SBaptiste Daroussin globfree(&g); 133cddcb259SBaptiste Daroussin errx(EXIT_FAILURE, "No SES devices found"); 134cddcb259SBaptiste Daroussin } 135cddcb259SBaptiste Daroussin for (i = 0; i < g.gl_pathc; i++) { 136cddcb259SBaptiste Daroussin /* ensure we only got numbers after ses */ 137cddcb259SBaptiste Daroussin if (strspn(g.gl_pathv[i] + 8, "0123456789") != 138cddcb259SBaptiste Daroussin strlen(g.gl_pathv[i] + 8)) 139cddcb259SBaptiste Daroussin continue; 140cddcb259SBaptiste Daroussin if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 141cddcb259SBaptiste Daroussin if (errno == EACCES) 142cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "enable to access SES device"); 143cddcb259SBaptiste Daroussin break; 144cddcb259SBaptiste Daroussin } 145cddcb259SBaptiste Daroussin 146cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) 147cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "ENCIOC_GETNELM"); 148cddcb259SBaptiste Daroussin 149cddcb259SBaptiste Daroussin objp = calloc(nobj, sizeof(encioc_element_t)); 150cddcb259SBaptiste Daroussin if (objp == NULL) 151cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "calloc()"); 152cddcb259SBaptiste Daroussin 153cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) 154cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 155cddcb259SBaptiste Daroussin 156cddcb259SBaptiste Daroussin for (j = 0; j < nobj; j++) { 157cddcb259SBaptiste Daroussin memset(&objdn, 0, sizeof(objdn)); 158cddcb259SBaptiste Daroussin objdn.elm_idx = objp[j].elm_idx; 159cddcb259SBaptiste Daroussin objdn.elm_names_size = 128; 160cddcb259SBaptiste Daroussin objdn.elm_devnames = calloc(128, sizeof(char)); 161cddcb259SBaptiste Daroussin if (objdn.elm_devnames == NULL) 162cddcb259SBaptiste Daroussin err(EXIT_FAILURE, "calloc()"); 163cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 164cddcb259SBaptiste Daroussin (caddr_t) &objdn) <0) 165cddcb259SBaptiste Daroussin continue; 166cddcb259SBaptiste Daroussin if (objdn.elm_names_len > 0) { 167cddcb259SBaptiste Daroussin if (all) { 168*4569e7cfSBaptiste Daroussin do_locate(fd, objdn.elm_idx, onoff); 169cddcb259SBaptiste Daroussin continue; 170cddcb259SBaptiste Daroussin } 171cddcb259SBaptiste Daroussin if (disk_match(objdn.elm_devnames, disk, len)) { 172*4569e7cfSBaptiste Daroussin do_locate(fd, objdn.elm_idx, onoff); 173cddcb259SBaptiste Daroussin break; 174cddcb259SBaptiste Daroussin } 175cddcb259SBaptiste Daroussin } 176cddcb259SBaptiste Daroussin } 177cddcb259SBaptiste Daroussin close(fd); 178cddcb259SBaptiste Daroussin i++; 179cddcb259SBaptiste Daroussin } 180cddcb259SBaptiste Daroussin globfree(&g); 181cddcb259SBaptiste Daroussin 182cddcb259SBaptiste Daroussin return (EXIT_SUCCESS); 183cddcb259SBaptiste Daroussin } 184cddcb259SBaptiste Daroussin 185cddcb259SBaptiste Daroussin static void 186cddcb259SBaptiste Daroussin usage(FILE *out) 187cddcb259SBaptiste Daroussin { 188cddcb259SBaptiste Daroussin int i; 189cddcb259SBaptiste Daroussin 190cddcb259SBaptiste Daroussin fprintf(out, "Usage: %s [command] [options]\n", getprogname()); 191cddcb259SBaptiste Daroussin fprintf(out, "Commands supported:\n"); 192cddcb259SBaptiste Daroussin for (i = 0; i < nbcmds; i++) 193cddcb259SBaptiste Daroussin fprintf(out, "\t%-15s%s\n", cmds[i].name, cmds[i].desc); 194cddcb259SBaptiste Daroussin } 195cddcb259SBaptiste Daroussin 196cddcb259SBaptiste Daroussin int 197cddcb259SBaptiste Daroussin main(int argc, char **argv) 198cddcb259SBaptiste Daroussin { 199cddcb259SBaptiste Daroussin int i; 200cddcb259SBaptiste Daroussin struct command *cmd = NULL; 201cddcb259SBaptiste Daroussin 202cddcb259SBaptiste Daroussin if (argc < 2) { 203cddcb259SBaptiste Daroussin warnx("Missing command"); 204cddcb259SBaptiste Daroussin usage(stderr); 205cddcb259SBaptiste Daroussin return (EXIT_FAILURE); 206cddcb259SBaptiste Daroussin } 207cddcb259SBaptiste Daroussin 208cddcb259SBaptiste Daroussin for (i = 0; i < nbcmds; i++) { 209cddcb259SBaptiste Daroussin if (strcmp(argv[1], cmds[i].name) == 0) { 210cddcb259SBaptiste Daroussin cmd = &cmds[i]; 211cddcb259SBaptiste Daroussin break; 212cddcb259SBaptiste Daroussin } 213cddcb259SBaptiste Daroussin } 214cddcb259SBaptiste Daroussin 215cddcb259SBaptiste Daroussin if (cmd == NULL) { 216cddcb259SBaptiste Daroussin warnx("unknown command %s", argv[1]); 217cddcb259SBaptiste Daroussin usage(stderr); 218cddcb259SBaptiste Daroussin return (EXIT_FAILURE); 219cddcb259SBaptiste Daroussin } 220cddcb259SBaptiste Daroussin 221cddcb259SBaptiste Daroussin argc-=2; 222cddcb259SBaptiste Daroussin argv+=2; 223cddcb259SBaptiste Daroussin 224cddcb259SBaptiste Daroussin return (cmd->exec(argc, argv)); 225cddcb259SBaptiste Daroussin } 226