1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 Sandvine Inc. 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/errno.h> 31 #include <sys/stat.h> 32 #include <err.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <time.h> 38 #include <unistd.h> 39 #include "mfiutil.h" 40 41 /* The autolearn period is given in seconds. */ 42 void 43 mfi_autolearn_period(FILE *fp, uint32_t period) 44 { 45 unsigned int d, h; 46 47 d = period / (24 * 3600); 48 h = (period % (24 * 3600)) / 3600; 49 50 if (d != 0) { 51 fprintf(fp, "%u day%s", d, d == 1 ? "" : "s"); 52 if (h != 0) 53 fprintf(fp, ", "); 54 } 55 if (h != 0) 56 fprintf(fp, "%u hour%s", h, h == 1 ? "" : "s"); 57 58 if (d == 0 && h == 0) 59 fprintf(fp, "less than 1 hour"); 60 } 61 62 /* The time to the next relearn is given in seconds since 1/1/2000. */ 63 void 64 mfi_next_learn_time(uint32_t next_learn_time, char *buf, size_t sz) 65 { 66 time_t basetime; 67 struct tm tm; 68 size_t len; 69 70 memset(&tm, 0, sizeof(tm)); 71 tm.tm_year = 100; 72 basetime = timegm(&tm); 73 basetime += (time_t)next_learn_time; 74 len = strlcpy(buf, ctime(&basetime), sz); 75 if (len < sz) 76 /* Get rid of the newline added by ctime(3). */ 77 buf[len - 1] = '\0'; 78 } 79 80 void 81 mfi_autolearn_mode(FILE *fp, uint8_t mode) 82 { 83 84 switch (mode) { 85 case 0: 86 fprintf(fp, "enabled"); 87 break; 88 case 1: 89 fprintf(fp, "disabled"); 90 break; 91 case 2: 92 fprintf(fp, "warn via event"); 93 break; 94 default: 95 fprintf(fp, "mode 0x%02x", mode); 96 break; 97 } 98 } 99 100 int 101 mfi_bbu_get_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp) 102 { 103 104 return (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_PROP, props, 105 sizeof(*props), NULL, 0, statusp)); 106 } 107 108 int 109 mfi_bbu_set_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp) 110 { 111 112 return (mfi_dcmd_command(fd, MFI_DCMD_BBU_SET_PROP, props, 113 sizeof(*props), NULL, 0, statusp)); 114 } 115 116 static int 117 start_bbu_learn(int ac, char **av __unused) 118 { 119 uint8_t status; 120 int error, fd; 121 122 status = MFI_STAT_OK; 123 error = 0; 124 125 if (ac != 1) { 126 warnx("start learn: unexpected arguments"); 127 return (EINVAL); 128 } 129 130 fd = mfi_open(mfi_device, O_RDWR); 131 if (fd < 0) { 132 error = errno; 133 warn("mfi_open"); 134 return (error); 135 } 136 137 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_START_LEARN, NULL, 0, NULL, 0, 138 &status) < 0) { 139 error = errno; 140 warn("Failed to start BBU learn"); 141 } else if (status != MFI_STAT_OK) { 142 warnx("Failed to start BBU learn: %s", mfi_status(status)); 143 error = EIO; 144 } 145 146 return (error); 147 } 148 MFI_COMMAND(start, learn, start_bbu_learn); 149 150 static int 151 update_bbu_props(int ac, char **av) 152 { 153 struct mfi_bbu_properties props; 154 unsigned long delay; 155 uint8_t status; 156 int error, fd; 157 char *mode, *endptr; 158 159 status = MFI_STAT_OK; 160 error = 0; 161 162 if (ac != 3) { 163 warnx("bbu: property and value required"); 164 return (EINVAL); 165 } 166 167 fd = mfi_open(mfi_device, O_RDWR); 168 if (fd < 0) { 169 error = errno; 170 warn("mfi_open"); 171 return (error); 172 } 173 174 if (mfi_bbu_get_props(fd, &props, &status) < 0) { 175 error = errno; 176 warn("Failed to get BBU properties"); 177 goto done; 178 } else if (status != MFI_STAT_OK) { 179 warnx("Failed to get BBU properties: %s", mfi_status(status)); 180 error = EIO; 181 goto done; 182 } 183 184 if (strcmp(av[1], "learn-delay") == 0) { 185 delay = strtoul(av[2], &endptr, 10); 186 if (strlen(av[2]) == 0 || *endptr != '\0' || delay > 255) { 187 warnx("Invalid learn delay '%s'", av[2]); 188 error = EINVAL; 189 goto done; 190 } 191 192 props.learn_delay_interval = delay; 193 } else if (strcmp(av[1], "autolearn-mode") == 0) { 194 mode = av[2]; 195 196 if (strcmp(av[2], "enable") == 0) 197 props.auto_learn_mode = 0; 198 else if (strcmp(av[2], "disable") == 0) 199 props.auto_learn_mode = 1; 200 else if (mode[0] >= '0' && mode[0] <= '2' && mode[1] == '\0') 201 props.auto_learn_mode = mode[0] - '0'; 202 else { 203 warnx("Invalid mode '%s'", mode); 204 error = EINVAL; 205 goto done; 206 } 207 } else if (strcmp(av[1], "bbu-mode") == 0) { 208 if (props.bbu_mode == 0) { 209 warnx("This BBU does not implement different modes"); 210 error = EINVAL; 211 goto done; 212 } 213 214 /* The mode must be an integer between 1 and 5. */ 215 mode = av[2]; 216 if (mode[0] < '1' || mode[0] > '5' || mode[1] != '\0') { 217 warnx("Invalid mode '%s'", mode); 218 error = EINVAL; 219 goto done; 220 } 221 222 props.bbu_mode = mode[0] - '0'; 223 } else { 224 warnx("bbu: Invalid command '%s'", av[1]); 225 error = EINVAL; 226 goto done; 227 } 228 229 if (mfi_bbu_set_props(fd, &props, &status) < 0) { 230 error = errno; 231 warn("Failed to set BBU properties"); 232 goto done; 233 } else if (status != MFI_STAT_OK) { 234 warnx("Failed to set BBU properties: %s", mfi_status(status)); 235 error = EIO; 236 goto done; 237 } 238 239 done: 240 close(fd); 241 242 return (error); 243 } 244 MFI_COMMAND(top, bbu, update_bbu_props); 245