svn commit: r249257 - in head: sys/dev/mfi usr.sbin/mfiutil

Mark Johnston markj at FreeBSD.org
Mon Apr 8 17:46:47 UTC 2013


Author: markj
Date: Mon Apr  8 17:46:45 2013
New Revision: 249257
URL: http://svnweb.freebsd.org/changeset/base/249257

Log:
  Add support for getting and setting BBU properties related to battery
  relearning. Specifically, add subcommands to mfiutil(8) which allow the
  user to set the BBU and autolearn modes when the firmware supports it,
  and add a subcommand which kicks off a battery relearn.
  
  Reviewed by:	sbruno, rstone
  Tested by:	sbruno
  Approved by:	rstone (co-mentor)
  MFC after:	2 weeks
  Sponsored by:	Sandvine Incorporated

Added:
  head/usr.sbin/mfiutil/mfi_bbu.c   (contents, props changed)
Modified:
  head/sys/dev/mfi/mfi_debug.c
  head/sys/dev/mfi/mfireg.h
  head/usr.sbin/mfiutil/Makefile
  head/usr.sbin/mfiutil/mfi_show.c
  head/usr.sbin/mfiutil/mfi_volume.c
  head/usr.sbin/mfiutil/mfiutil.8
  head/usr.sbin/mfiutil/mfiutil.c
  head/usr.sbin/mfiutil/mfiutil.h

Modified: head/sys/dev/mfi/mfi_debug.c
==============================================================================
--- head/sys/dev/mfi/mfi_debug.c	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/sys/dev/mfi/mfi_debug.c	Mon Apr  8 17:46:45 2013	(r249257)
@@ -168,6 +168,15 @@ mfi_print_dcmd(struct mfi_softc *sc, dev
 	case MFI_DCMD_LD_MAP_GET_INFO:
 		opcode = "LD_MAP_GET_INFO";
 		break;
+	case MFI_DCMD_BBU_START_LEARN:
+		opcode = "BBU_START_LEARN";
+		break;
+	case MFI_DCMD_BBU_GET_PROP:
+		opcode = "BBU_GET_PROP";
+		break;
+	case MFI_DCMD_BBU_SET_PROP:
+		opcode = "BBU_SET_PROP";
+		break;
 	default:
 		opcode = "UNKNOWN";
 		break;

Modified: head/sys/dev/mfi/mfireg.h
==============================================================================
--- head/sys/dev/mfi/mfireg.h	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/sys/dev/mfi/mfireg.h	Mon Apr  8 17:46:45 2013	(r249257)
@@ -234,6 +234,9 @@ typedef enum {
 	MFI_DCMD_BBU_GET_STATUS =	0x05010000,
 	MFI_DCMD_BBU_GET_CAPACITY_INFO =0x05020000,
 	MFI_DCMD_BBU_GET_DESIGN_INFO =	0x05030000,
+	MFI_DCMD_BBU_START_LEARN =	0x05040000,
+	MFI_DCMD_BBU_GET_PROP =		0x05050100,
+	MFI_DCMD_BBU_SET_PROP =		0x05050200,
 	MFI_DCMD_CLUSTER =		0x08000000,
 	MFI_DCMD_CLUSTER_RESET_ALL =	0x08010100,
 	MFI_DCMD_CLUSTER_RESET_LD =	0x08010200
@@ -1367,6 +1370,15 @@ struct mfi_bbu_state {
 	uint8_t			reserved[21];
 } __packed;
 
+struct mfi_bbu_properties {
+	uint32_t		auto_learn_period;
+	uint32_t		next_learn_time;
+	uint8_t			learn_delay_interval;
+	uint8_t			auto_learn_mode;
+	uint8_t			bbu_mode;
+	uint8_t			reserved[21];
+} __packed;
+
 union mfi_bbu_status_detail {
 	struct mfi_ibbu_state	ibbu;
 	struct mfi_bbu_state	bbu;

Modified: head/usr.sbin/mfiutil/Makefile
==============================================================================
--- head/usr.sbin/mfiutil/Makefile	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/Makefile	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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

Added: head/usr.sbin/mfiutil/mfi_bbu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/mfiutil/mfi_bbu.c	Mon Apr  8 17:46:45 2013	(r249257)
@@ -0,0 +1,252 @@
+/*-
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * 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);

Modified: head/usr.sbin/mfiutil/mfi_show.c
==============================================================================
--- head/usr.sbin/mfiutil/mfi_show.c	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/mfi_show.c	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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) {

Modified: head/usr.sbin/mfiutil/mfi_volume.c
==============================================================================
--- head/usr.sbin/mfiutil/mfi_volume.c	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/mfi_volume.c	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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;

Modified: head/usr.sbin/mfiutil/mfiutil.8
==============================================================================
--- head/usr.sbin/mfiutil/mfiutil.8	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/mfiutil.8	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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 ope
 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:

Modified: head/usr.sbin/mfiutil/mfiutil.c
==============================================================================
--- head/usr.sbin/mfiutil/mfiutil.c	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/mfiutil.c	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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");

Modified: head/usr.sbin/mfiutil/mfiutil.h
==============================================================================
--- head/usr.sbin/mfiutil/mfiutil.h	Mon Apr  8 15:36:26 2013	(r249256)
+++ head/usr.sbin/mfiutil/mfiutil.h	Mon Apr  8 17:46:45 2013	(r249257)
@@ -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);


More information about the svn-src-all mailing list