1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/log.h" 36 #include "spdk/likely.h" 37 #include "spdk/env.h" 38 #include "spdk/vmd.h" 39 40 enum app_action { 41 APP_ACTION_SET, 42 APP_ACTION_GET, 43 APP_ACTION_NOP, 44 }; 45 46 struct app_opts { 47 const char *app_name; 48 struct spdk_pci_addr pci_addr; 49 bool all_devices; 50 enum app_action action; 51 enum spdk_vmd_led_state led_state; 52 }; 53 54 struct app_opts g_opts = { 55 .all_devices = true, 56 .action = APP_ACTION_GET, 57 .led_state = SPDK_VMD_LED_STATE_UNKNOWN, 58 }; 59 60 static const char *g_led_states[] = { 61 [SPDK_VMD_LED_STATE_OFF] = "off", 62 [SPDK_VMD_LED_STATE_IDENTIFY] = "identify", 63 [SPDK_VMD_LED_STATE_FAULT] = "fault", 64 [SPDK_VMD_LED_STATE_REBUILD] = "rebuild", 65 [SPDK_VMD_LED_STATE_UNKNOWN] = "unknown", 66 }; 67 68 static void 69 usage(void) 70 { 71 printf("Usage: %s [-d] [-s STATE] [-r TRADDR]\n", g_opts.app_name); 72 printf("\n"); 73 printf("Options:\n"); 74 printf(" -d enables debug logs from the VMD module\n"); 75 printf(" -s STATE sets the state of the LEDs. Available states are:\n"); 76 printf(" off, identify, fault, rebuild\n"); 77 printf(" -r TRADDR uses device identified by TRADDR\n"); 78 printf(" -h shows this help\n"); 79 } 80 81 static int 82 parse_args(int argc, char **argv) 83 { 84 int led_state; 85 int op; 86 87 g_opts.app_name = argv[0]; 88 89 while ((op = getopt(argc, argv, "dhr:s:")) != -1) { 90 switch (op) { 91 case 'r': 92 if (spdk_pci_addr_parse(&g_opts.pci_addr, optarg)) { 93 fprintf(stderr, "Unable to parse PCI address: %s\n", optarg); 94 return -EINVAL; 95 } 96 97 g_opts.all_devices = false; 98 break; 99 100 case 'd': 101 #ifdef DEBUG 102 spdk_log_set_print_level(SPDK_LOG_DEBUG); 103 spdk_log_set_flag("vmd"); 104 break; 105 #else 106 fprintf(stderr, "%s must be rebuilt with --enable-debug for the -d flag\n", 107 argv[0]); 108 return -EINVAL; 109 #endif 110 case 's': 111 for (led_state = SPDK_VMD_LED_STATE_OFF; 112 led_state <= SPDK_VMD_LED_STATE_REBUILD; 113 led_state++) { 114 if (strcmp(optarg, g_led_states[led_state]) == 0) { 115 g_opts.led_state = (enum spdk_vmd_led_state)led_state; 116 break; 117 } 118 } 119 120 if (g_opts.led_state == SPDK_VMD_LED_STATE_UNKNOWN) { 121 fprintf(stderr, "Invalid LED state\n"); 122 return -EINVAL; 123 } 124 125 g_opts.action = APP_ACTION_SET; 126 break; 127 128 case 'h': 129 g_opts.action = APP_ACTION_NOP; 130 usage(); 131 break; 132 133 default: 134 return -EINVAL; 135 } 136 } 137 138 return 0; 139 } 140 141 int 142 main(int argc, char **argv) 143 { 144 struct spdk_env_opts opts; 145 struct spdk_pci_device *pci_device; 146 enum spdk_vmd_led_state led_state; 147 char addr_buf[128]; 148 int rc, status = 0; 149 150 if (parse_args(argc, argv) != 0) { 151 usage(); 152 return 1; 153 } 154 155 if (g_opts.action == APP_ACTION_NOP) { 156 return 0; 157 } 158 159 spdk_env_opts_init(&opts); 160 opts.name = "led"; 161 162 if (spdk_env_init(&opts) < 0) { 163 fprintf(stderr, "Unable to initialize SPDK environment\n"); 164 return 1; 165 } 166 167 rc = spdk_vmd_init(); 168 if (rc) { 169 fprintf(stderr, "Unable to initialize VMD subsystem\n"); 170 return 1; 171 } 172 173 for (pci_device = spdk_pci_get_first_device(); pci_device != NULL; 174 pci_device = spdk_pci_get_next_device(pci_device)) { 175 if (strcmp(spdk_pci_device_get_type(pci_device), "vmd") != 0) { 176 continue; 177 } 178 179 if (!g_opts.all_devices && 180 spdk_pci_addr_compare(&g_opts.pci_addr, &pci_device->addr) != 0) { 181 continue; 182 } 183 184 rc = spdk_pci_addr_fmt(addr_buf, sizeof(addr_buf), &pci_device->addr); 185 if (rc != 0) { 186 fprintf(stderr, "Failed to format VMD's PCI address\n"); 187 status = 1; 188 break; 189 } 190 191 if (g_opts.action == APP_ACTION_GET) { 192 rc = spdk_vmd_get_led_state(pci_device, &led_state); 193 if (spdk_unlikely(rc != 0)) { 194 fprintf(stderr, "Failed to retrieve the state of the LED on %s\n", 195 addr_buf); 196 status = 1; 197 break; 198 } 199 200 printf("%s: %s\n", addr_buf, g_led_states[led_state]); 201 } else { 202 rc = spdk_vmd_set_led_state(pci_device, g_opts.led_state); 203 if (spdk_unlikely(rc != 0)) { 204 fprintf(stderr, "Failed to set LED state on %s\n", addr_buf); 205 status = 1; 206 break; 207 } 208 } 209 } 210 211 return status; 212 } 213