1249257Smarkj/*- 2249257Smarkj * Copyright (c) 2013 Sandvine Inc. 3249257Smarkj * All rights reserved. 4249257Smarkj * 5249257Smarkj * Redistribution and use in source and binary forms, with or without 6249257Smarkj * modification, are permitted provided that the following conditions 7249257Smarkj * are met: 8249257Smarkj * 1. Redistributions of source code must retain the above copyright 9249257Smarkj * notice, this list of conditions and the following disclaimer. 10249257Smarkj * 2. Redistributions in binary form must reproduce the above copyright 11249257Smarkj * notice, this list of conditions and the following disclaimer in the 12249257Smarkj * documentation and/or other materials provided with the distribution. 13249257Smarkj * 14249257Smarkj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15249257Smarkj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16249257Smarkj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17249257Smarkj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18249257Smarkj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19249257Smarkj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20249257Smarkj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249257Smarkj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249257Smarkj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23249257Smarkj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24249257Smarkj * SUCH DAMAGE. 25249257Smarkj * 26249257Smarkj * $FreeBSD: releng/11.0/usr.sbin/mfiutil/mfi_bbu.c 249258 2013-04-08 18:25:07Z markj $ 27249257Smarkj */ 28249257Smarkj 29249257Smarkj#include <sys/param.h> 30249257Smarkj#include <sys/errno.h> 31249257Smarkj#include <sys/stat.h> 32249257Smarkj#include <err.h> 33249257Smarkj#include <fcntl.h> 34249257Smarkj#include <stdio.h> 35249257Smarkj#include <stdlib.h> 36249257Smarkj#include <string.h> 37249257Smarkj#include <time.h> 38249257Smarkj#include <unistd.h> 39249257Smarkj#include "mfiutil.h" 40249257Smarkj 41249257Smarkj/* The autolearn period is given in seconds. */ 42249257Smarkjvoid 43249257Smarkjmfi_autolearn_period(uint32_t period, char *buf, size_t sz) 44249257Smarkj{ 45249257Smarkj unsigned int d, h; 46249257Smarkj char *tmp; 47249257Smarkj 48249257Smarkj d = period / (24 * 3600); 49249257Smarkj h = (period % (24 * 3600)) / 3600; 50249257Smarkj 51249257Smarkj tmp = buf; 52249257Smarkj if (d != 0) { 53249257Smarkj tmp += snprintf(buf, sz, "%u day%s", d, d == 1 ? "" : "s"); 54249257Smarkj sz -= tmp - buf; 55249257Smarkj if (h != 0) { 56249257Smarkj tmp += snprintf(tmp, sz, ", "); 57249257Smarkj sz -= 2; 58249257Smarkj } 59249257Smarkj } 60249257Smarkj if (h != 0) 61249257Smarkj snprintf(tmp, sz, "%u hour%s", h, h == 1 ? "" : "s"); 62249257Smarkj 63249257Smarkj if (d == 0 && h == 0) 64249257Smarkj snprintf(tmp, sz, "less than 1 hour"); 65249257Smarkj} 66249257Smarkj 67249257Smarkj/* The time to the next relearn is given in seconds since 1/1/2000. */ 68249257Smarkjvoid 69249257Smarkjmfi_next_learn_time(uint32_t next_learn_time, char *buf, size_t sz) 70249257Smarkj{ 71249257Smarkj time_t basetime; 72249257Smarkj struct tm tm; 73249257Smarkj size_t len; 74249257Smarkj 75249257Smarkj memset(&tm, 0, sizeof(tm)); 76249257Smarkj tm.tm_year = 100; 77249257Smarkj basetime = timegm(&tm); 78249257Smarkj basetime += (time_t)next_learn_time; 79249257Smarkj len = snprintf(buf, sz, "%s", ctime(&basetime)); 80249257Smarkj if (len > 0) 81249257Smarkj /* Get rid of the newline added by ctime(3). */ 82249257Smarkj buf[len - 1] = '\0'; 83249257Smarkj} 84249257Smarkj 85249257Smarkjvoid 86249257Smarkjmfi_autolearn_mode(uint8_t mode, char *buf, size_t sz) 87249257Smarkj{ 88249257Smarkj 89249257Smarkj switch (mode) { 90249257Smarkj case 0: 91249257Smarkj snprintf(buf, sz, "enabled"); 92249257Smarkj break; 93249257Smarkj case 1: 94249257Smarkj snprintf(buf, sz, "disabled"); 95249257Smarkj break; 96249257Smarkj case 2: 97249257Smarkj snprintf(buf, sz, "warn via event"); 98249257Smarkj break; 99249257Smarkj default: 100249257Smarkj snprintf(buf, sz, "mode 0x%02x", mode); 101249257Smarkj break; 102249257Smarkj } 103249257Smarkj} 104249257Smarkj 105249257Smarkjint 106249257Smarkjmfi_bbu_get_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp) 107249257Smarkj{ 108249257Smarkj 109249257Smarkj return (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_PROP, props, 110249257Smarkj sizeof(*props), NULL, 0, statusp)); 111249257Smarkj} 112249257Smarkj 113249257Smarkjint 114249257Smarkjmfi_bbu_set_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp) 115249257Smarkj{ 116249257Smarkj 117249257Smarkj return (mfi_dcmd_command(fd, MFI_DCMD_BBU_SET_PROP, props, 118249257Smarkj sizeof(*props), NULL, 0, statusp)); 119249257Smarkj} 120249257Smarkj 121249257Smarkjstatic int 122249257Smarkjstart_bbu_learn(int ac, char **av __unused) 123249257Smarkj{ 124249257Smarkj uint8_t status; 125249257Smarkj int error, fd; 126249257Smarkj 127249257Smarkj status = MFI_STAT_OK; 128249257Smarkj error = 0; 129249257Smarkj 130249257Smarkj if (ac != 1) { 131249257Smarkj warnx("start learn: unexpected arguments"); 132249257Smarkj return (EINVAL); 133249257Smarkj } 134249257Smarkj 135249257Smarkj fd = mfi_open(mfi_unit, O_RDWR); 136249257Smarkj if (fd < 0) { 137249257Smarkj error = errno; 138249257Smarkj warn("mfi_open"); 139249257Smarkj return (error); 140249257Smarkj } 141249257Smarkj 142249257Smarkj if (mfi_dcmd_command(fd, MFI_DCMD_BBU_START_LEARN, NULL, 0, NULL, 0, 143249257Smarkj &status) < 0) { 144249257Smarkj error = errno; 145249257Smarkj warn("Failed to start BBU learn"); 146249257Smarkj } else if (status != MFI_STAT_OK) { 147249257Smarkj warnx("Failed to start BBU learn: %s", mfi_status(status)); 148249257Smarkj error = EIO; 149249257Smarkj } 150249257Smarkj 151249257Smarkj return (error); 152249257Smarkj} 153249257SmarkjMFI_COMMAND(start, learn, start_bbu_learn); 154249257Smarkj 155249257Smarkjstatic int 156249257Smarkjupdate_bbu_props(int ac, char **av) 157249257Smarkj{ 158249257Smarkj struct mfi_bbu_properties props; 159249257Smarkj unsigned long delay; 160249257Smarkj uint8_t status; 161249257Smarkj int error, fd; 162249257Smarkj char *mode, *endptr; 163249257Smarkj 164249257Smarkj status = MFI_STAT_OK; 165249257Smarkj error = 0; 166249257Smarkj 167249257Smarkj if (ac != 3) { 168249257Smarkj warnx("bbu: property and value required"); 169249257Smarkj return (EINVAL); 170249257Smarkj } 171249257Smarkj 172249257Smarkj fd = mfi_open(mfi_unit, O_RDWR); 173249257Smarkj if (fd < 0) { 174249257Smarkj error = errno; 175249257Smarkj warn("mfi_open"); 176249257Smarkj return (error); 177249257Smarkj } 178249257Smarkj 179249257Smarkj if (mfi_bbu_get_props(fd, &props, &status) < 0) { 180249257Smarkj error = errno; 181249257Smarkj warn("Failed to get BBU properties"); 182249257Smarkj goto done; 183249257Smarkj } else if (status != MFI_STAT_OK) { 184249257Smarkj warnx("Failed to get BBU properties: %s", mfi_status(status)); 185249257Smarkj error = EIO; 186249257Smarkj goto done; 187249257Smarkj } 188249257Smarkj 189249257Smarkj if (strcmp(av[1], "learn-delay") == 0) { 190249257Smarkj delay = strtoul(av[2], &endptr, 10); 191249257Smarkj if (strlen(av[2]) == 0 || *endptr != '\0' || delay > 255) { 192249257Smarkj warnx("Invalid learn delay '%s'", av[2]); 193249257Smarkj error = EINVAL; 194249257Smarkj goto done; 195249257Smarkj } 196249257Smarkj 197249257Smarkj props.learn_delay_interval = delay; 198249257Smarkj } else if (strcmp(av[1], "autolearn-mode") == 0) { 199249257Smarkj mode = av[2]; 200249257Smarkj 201249257Smarkj if (strcmp(av[2], "enable") == 0) 202249257Smarkj props.auto_learn_mode = 0; 203249257Smarkj else if (strcmp(av[2], "disable") == 0) 204249257Smarkj props.auto_learn_mode = 1; 205249257Smarkj else if (mode[0] >= '0' && mode[0] <= '2' && mode[1] == '\0') 206249257Smarkj props.auto_learn_mode = mode[0] - '0'; 207249257Smarkj else { 208249257Smarkj warnx("Invalid mode '%s'", mode); 209249257Smarkj error = EINVAL; 210249257Smarkj goto done; 211249257Smarkj } 212249257Smarkj } else if (strcmp(av[1], "bbu-mode") == 0) { 213249257Smarkj if (props.bbu_mode == 0) { 214249257Smarkj warnx("This BBU does not implement different modes"); 215249257Smarkj error = EINVAL; 216249257Smarkj goto done; 217249257Smarkj } 218249257Smarkj 219249257Smarkj /* The mode must be an integer between 1 and 5. */ 220249257Smarkj mode = av[2]; 221249257Smarkj if (mode[0] < '1' || mode[0] > '5' || mode[1] != '\0') { 222249257Smarkj warnx("Invalid mode '%s'", mode); 223249257Smarkj error = EINVAL; 224249257Smarkj goto done; 225249257Smarkj } 226249257Smarkj 227249257Smarkj props.bbu_mode = mode[0] - '0'; 228249257Smarkj } else { 229249257Smarkj warnx("bbu: Invalid command '%s'", av[1]); 230249257Smarkj error = EINVAL; 231249257Smarkj goto done; 232249257Smarkj } 233249257Smarkj 234249257Smarkj if (mfi_bbu_set_props(fd, &props, &status) < 0) { 235249257Smarkj error = errno; 236249257Smarkj warn("Failed to set BBU properties"); 237249257Smarkj goto done; 238249257Smarkj } else if (status != MFI_STAT_OK) { 239249257Smarkj warnx("Failed to set BBU properties: %s", mfi_status(status)); 240249257Smarkj error = EIO; 241249257Smarkj goto done; 242249257Smarkj } 243249257Smarkj 244249257Smarkjdone: 245249257Smarkj close(fd); 246249257Smarkj 247249257Smarkj return (error); 248249257Smarkj} 249249257SmarkjMFI_COMMAND(top, bbu, update_bbu_props); 250