summaryrefslogtreecommitdiffstats
path: root/usr.sbin/mfiutil
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2013-04-12 20:48:55 +0000
committersjg <sjg@FreeBSD.org>2013-04-12 20:48:55 +0000
commit97d8b9495668afa398ab17c8c5f7e223b5fd2e89 (patch)
tree54038c9ac32a45f8741dcc23fb9a8ffc0e15ff89 /usr.sbin/mfiutil
parent5ee3bfdb338e7c80af29a67f4425c4be24c7b866 (diff)
parent086d73aef6d0ab7d21daa2076fdc8d25961f9b05 (diff)
downloadFreeBSD-src-97d8b9495668afa398ab17c8c5f7e223b5fd2e89.zip
FreeBSD-src-97d8b9495668afa398ab17c8c5f7e223b5fd2e89.tar.gz
sync from head
Diffstat (limited to 'usr.sbin/mfiutil')
-rw-r--r--usr.sbin/mfiutil/Makefile4
-rw-r--r--usr.sbin/mfiutil/mfi_bbu.c249
-rw-r--r--usr.sbin/mfiutil/mfi_show.c29
-rw-r--r--usr.sbin/mfiutil/mfi_volume.c3
-rw-r--r--usr.sbin/mfiutil/mfiutil.833
-rw-r--r--usr.sbin/mfiutil/mfiutil.c2
-rw-r--r--usr.sbin/mfiutil/mfiutil.h7
7 files changed, 323 insertions, 4 deletions
diff --git a/usr.sbin/mfiutil/Makefile b/usr.sbin/mfiutil/Makefile
index e100358..c460b3f 100644
--- a/usr.sbin/mfiutil/Makefile
+++ b/usr.sbin/mfiutil/Makefile
@@ -1,8 +1,8 @@
# $FreeBSD$
PROG= mfiutil
-SRCS= mfiutil.c mfi_cmd.c mfi_config.c mfi_drive.c mfi_evt.c mfi_flash.c \
- mfi_patrol.c mfi_show.c mfi_volume.c
+SRCS= mfiutil.c mfi_bbu.c mfi_cmd.c mfi_config.c mfi_drive.c mfi_evt.c \
+ mfi_flash.c mfi_patrol.c mfi_show.c mfi_volume.c
MAN8= mfiutil.8
CFLAGS+= -fno-builtin-strftime
diff --git a/usr.sbin/mfiutil/mfi_bbu.c b/usr.sbin/mfiutil/mfi_bbu.c
new file mode 100644
index 0000000..db16367
--- /dev/null
+++ b/usr.sbin/mfiutil/mfi_bbu.c
@@ -0,0 +1,249 @@
+/*-
+ * Copyright (c) 2013 Sandvine Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "mfiutil.h"
+
+/* The autolearn period is given in seconds. */
+void
+mfi_autolearn_period(uint32_t period, char *buf, size_t sz)
+{
+ unsigned int d, h;
+ char *tmp;
+
+ d = period / (24 * 3600);
+ h = (period % (24 * 3600)) / 3600;
+
+ tmp = buf;
+ if (d != 0) {
+ tmp += snprintf(buf, sz, "%u day%s", d, d == 1 ? "" : "s");
+ sz -= tmp - buf;
+ if (h != 0) {
+ tmp += snprintf(tmp, sz, ", ");
+ sz -= 2;
+ }
+ }
+ if (h != 0)
+ snprintf(tmp, sz, "%u hour%s", h, h == 1 ? "" : "s");
+
+ if (d == 0 && h == 0)
+ snprintf(tmp, sz, "less than 1 hour");
+}
+
+/* The time to the next relearn is given in seconds since 1/1/2000. */
+void
+mfi_next_learn_time(uint32_t next_learn_time, char *buf, size_t sz)
+{
+ time_t basetime;
+ struct tm tm;
+ size_t len;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 100;
+ basetime = timegm(&tm);
+ basetime += (time_t)next_learn_time;
+ len = snprintf(buf, sz, "%s", ctime(&basetime));
+ if (len > 0)
+ /* Get rid of the newline added by ctime(3). */
+ buf[len - 1] = '\0';
+}
+
+void
+mfi_autolearn_mode(uint8_t mode, char *buf, size_t sz)
+{
+
+ switch (mode) {
+ case 0:
+ snprintf(buf, sz, "enabled");
+ break;
+ case 1:
+ snprintf(buf, sz, "disabled");
+ break;
+ case 2:
+ snprintf(buf, sz, "warn via event");
+ break;
+ default:
+ snprintf(buf, sz, "mode 0x%02x", mode);
+ break;
+ }
+}
+
+int
+mfi_bbu_get_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp)
+{
+
+ return (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_PROP, props,
+ sizeof(*props), NULL, 0, statusp));
+}
+
+int
+mfi_bbu_set_props(int fd, struct mfi_bbu_properties *props, uint8_t *statusp)
+{
+
+ return (mfi_dcmd_command(fd, MFI_DCMD_BBU_SET_PROP, props,
+ sizeof(*props), NULL, 0, statusp));
+}
+
+static int
+start_bbu_learn(int ac, char **av __unused)
+{
+ uint8_t status;
+ int error, fd;
+
+ status = MFI_STAT_OK;
+ error = 0;
+
+ if (ac != 1) {
+ warnx("start learn: unexpected arguments");
+ return (EINVAL);
+ }
+
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ if (mfi_dcmd_command(fd, MFI_DCMD_BBU_START_LEARN, NULL, 0, NULL, 0,
+ &status) < 0) {
+ error = errno;
+ warn("Failed to start BBU learn");
+ } else if (status != MFI_STAT_OK) {
+ warnx("Failed to start BBU learn: %s", mfi_status(status));
+ error = EIO;
+ }
+
+ return (error);
+}
+MFI_COMMAND(start, learn, start_bbu_learn);
+
+static int
+update_bbu_props(int ac, char **av)
+{
+ struct mfi_bbu_properties props;
+ unsigned long delay;
+ uint8_t status;
+ int error, fd;
+ char *mode, *endptr;
+
+ status = MFI_STAT_OK;
+ error = 0;
+
+ if (ac != 3) {
+ warnx("bbu: property and value required");
+ return (EINVAL);
+ }
+
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ if (mfi_bbu_get_props(fd, &props, &status) < 0) {
+ error = errno;
+ warn("Failed to get BBU properties");
+ goto done;
+ } else if (status != MFI_STAT_OK) {
+ warnx("Failed to get BBU properties: %s", mfi_status(status));
+ error = EIO;
+ goto done;
+ }
+
+ if (strcmp(av[1], "learn-delay") == 0) {
+ delay = strtoul(av[2], &endptr, 10);
+ if (strlen(av[2]) == 0 || *endptr != '\0' || delay > 255) {
+ warnx("Invalid learn delay '%s'", av[2]);
+ error = EINVAL;
+ goto done;
+ }
+
+ props.learn_delay_interval = delay;
+ } else if (strcmp(av[1], "autolearn-mode") == 0) {
+ mode = av[2];
+
+ if (strcmp(av[2], "enable") == 0)
+ props.auto_learn_mode = 0;
+ else if (strcmp(av[2], "disable") == 0)
+ props.auto_learn_mode = 1;
+ else if (mode[0] >= '0' && mode[0] <= '2' && mode[1] == '\0')
+ props.auto_learn_mode = mode[0] - '0';
+ else {
+ warnx("Invalid mode '%s'", mode);
+ error = EINVAL;
+ goto done;
+ }
+ } else if (strcmp(av[1], "bbu-mode") == 0) {
+ if (props.bbu_mode == 0) {
+ warnx("This BBU does not implement different modes");
+ error = EINVAL;
+ goto done;
+ }
+
+ /* The mode must be an integer between 1 and 5. */
+ mode = av[2];
+ if (mode[0] < '1' || mode[0] > '5' || mode[1] != '\0') {
+ warnx("Invalid mode '%s'", mode);
+ error = EINVAL;
+ goto done;
+ }
+
+ props.bbu_mode = mode[0] - '0';
+ } else {
+ warnx("bbu: Invalid command '%s'", av[1]);
+ error = EINVAL;
+ goto done;
+ }
+
+ if (mfi_bbu_set_props(fd, &props, &status) < 0) {
+ error = errno;
+ warn("Failed to set BBU properties");
+ goto done;
+ } else if (status != MFI_STAT_OK) {
+ warnx("Failed to set BBU properties: %s", mfi_status(status));
+ error = EIO;
+ goto done;
+ }
+
+done:
+ close(fd);
+
+ return (error);
+}
+MFI_COMMAND(top, bbu, update_bbu_props);
diff --git a/usr.sbin/mfiutil/mfi_show.c b/usr.sbin/mfiutil/mfi_show.c
index be395bb..06721c2 100644
--- a/usr.sbin/mfiutil/mfi_show.c
+++ b/usr.sbin/mfiutil/mfi_show.c
@@ -140,9 +140,11 @@ show_battery(int ac, char **av __unused)
{
struct mfi_bbu_capacity_info cap;
struct mfi_bbu_design_info design;
+ struct mfi_bbu_properties props;
struct mfi_bbu_status stat;
uint8_t status;
- int comma, error, fd, show_capacity;
+ int comma, error, fd, show_capacity, show_props;
+ char buf[32];
if (ac != 1) {
warnx("show battery: extra arguments");
@@ -186,6 +188,14 @@ show_battery(int ac, char **av __unused)
return (error);
}
+ if (mfi_bbu_get_props(fd, &props, &status) < 0) {
+ error = errno;
+ warn("Failed to get properties");
+ close(fd);
+ return (error);
+ }
+ show_props = (status == MFI_STAT_OK);
+
printf("mfi%d: Battery State:\n", mfi_unit);
printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f,
design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff);
@@ -205,6 +215,23 @@ show_battery(int ac, char **av __unused)
printf(" Design Voltage: %d mV\n", design.design_voltage);
printf(" Current Voltage: %d mV\n", stat.voltage);
printf(" Temperature: %d C\n", stat.temperature);
+ if (show_props) {
+ mfi_autolearn_period(props.auto_learn_period, buf, sizeof(buf));
+ printf(" Autolearn period: %s\n", buf);
+ if (props.auto_learn_mode != 0)
+ snprintf(buf, sizeof(buf), "never");
+ else
+ mfi_next_learn_time(props.next_learn_time, buf,
+ sizeof(buf));
+ printf(" Next learn time: %s\n", buf);
+ printf(" Learn delay interval: %u hour%s\n",
+ props.learn_delay_interval,
+ props.learn_delay_interval != 1 ? "s" : "");
+ mfi_autolearn_mode(props.auto_learn_mode, buf, sizeof(buf));
+ printf(" Autolearn mode: %s\n", buf);
+ if (props.bbu_mode != 0)
+ printf(" BBU Mode: %d\n", props.bbu_mode);
+ }
printf(" Status:");
comma = 0;
if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) {
diff --git a/usr.sbin/mfiutil/mfi_volume.c b/usr.sbin/mfiutil/mfi_volume.c
index 49417d0..2306256 100644
--- a/usr.sbin/mfiutil/mfi_volume.c
+++ b/usr.sbin/mfiutil/mfi_volume.c
@@ -363,7 +363,8 @@ volume_cache(int ac, char **av)
break;
}
if (props.default_cache_policy != props.current_cache_policy)
- printf("Cache Disabled Due to Dead Battery\n");
+ printf(
+ "Cache disabled due to dead battery or ongoing battery relearn\n");
error = 0;
} else {
new = props;
diff --git a/usr.sbin/mfiutil/mfiutil.8 b/usr.sbin/mfiutil/mfiutil.8
index b1be5d9..5468617 100644
--- a/usr.sbin/mfiutil/mfiutil.8
+++ b/usr.sbin/mfiutil/mfiutil.8
@@ -141,6 +141,12 @@
.Nm
.Op Fl u Ar unit
.Cm flash Ar file
+.Nm
+.Op Fl u Ar unit
+.Cm start learn
+.Nm
+.Op Fl u Ar unit
+.Cm bbu Ar setting Ar value
.Sh DESCRIPTION
The
.Nm
@@ -565,6 +571,33 @@ Stop a currently running patrol read operation.
Updates the flash on the controller with the firmware stored in
.Ar file .
A reboot is required for the new firmware to take effect.
+.It Cm start learn
+Start a battery relearn.
+.It Cm bbu Ar setting Ar value
+Update battery backup unit (BBU) properties related to battery relearning.
+The following settings are configurable:
+.Bl -tag -width indent
+.It Cm learn-delay
+Add a delay to the next scheduled battery relearn event. This setting is
+given in hours and must lie in the range of 0 to 255.
+.It Cm autolearn-mode
+Enable or disable automatic periodic battery relearning.
+The setting may be set to
+.Dq enable
+or
+.Dq disable
+to respectively enable or disable the relearn cycle.
+Alternatively, a mode of 0, 1 or 2 may be given.
+Mode 0 enables periodic relearning, mode 1 disables it, and mode 2 disables
+it and logs a warning to the event log when it detects that a battery relearn
+should be performed.
+.It Cm bbu-mode
+Set the BBU's mode of operation. This setting is not supported by all BBUs.
+Where it is supported, the possible values are the integers between 1 and 5
+inclusive.
+Modes 1, 2 and 3 enable a transparent learn cycle, whereas modes 4 and 5 do not.
+The BBU's data retention time is greater when transparent learning is not used.
+.El
.El
.Sh EXAMPLES
Configure the cache for volume mfid0 to cache only writes:
diff --git a/usr.sbin/mfiutil/mfiutil.c b/usr.sbin/mfiutil/mfiutil.c
index 79c6a4b..7488e24 100644
--- a/usr.sbin/mfiutil/mfiutil.c
+++ b/usr.sbin/mfiutil/mfiutil.c
@@ -84,6 +84,8 @@ usage(void)
fprintf(stderr, " start patrol - start a patrol read\n");
fprintf(stderr, " stop patrol - stop a patrol read\n");
fprintf(stderr, " flash <firmware>\n");
+ fprintf(stderr, " start learn - start a BBU relearn\n");
+ fprintf(stderr, " bbu <setting> <value> - set BBU properties\n");
#ifdef DEBUG
fprintf(stderr, " debug - debug 'show config'\n");
fprintf(stderr, " dump - display 'saved' config\n");
diff --git a/usr.sbin/mfiutil/mfiutil.h b/usr.sbin/mfiutil/mfiutil.h
index 687bdd9..8a544c2 100644
--- a/usr.sbin/mfiutil/mfiutil.h
+++ b/usr.sbin/mfiutil/mfiutil.h
@@ -152,6 +152,13 @@ int mfi_reconfig_supported(void);
const char *mfi_status(u_int status_code);
const char *mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id,
uint32_t def);
+int mfi_bbu_get_props(int fd, struct mfi_bbu_properties *props,
+ uint8_t *statusp);
+int mfi_bbu_set_props(int fd, struct mfi_bbu_properties *props,
+ uint8_t *statusp);
+void mfi_autolearn_period(uint32_t, char *, size_t);
+void mfi_next_learn_time(uint32_t, char *, size_t);
+void mfi_autolearn_mode(uint8_t, char *, size_t);
void scan_firmware(struct mfi_info_component *comp);
void display_firmware(struct mfi_info_component *comp, const char *tag);
OpenPOWER on IntegriCloud