From 7dc99ed9e54612fdb495ce7b7b789497534c10cd Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Mon, 1 Aug 2011 20:09:52 +0200
Subject: [PATCH 1/3] mfi(4) & mfiutil(8): Sync with FreeBSD

---
 sys/dev/raid/mfi/mfi.c        |   45 ++++----
 sys/dev/raid/mfi/mfi_cam.c    |    5 +-
 sys/dev/raid/mfi/mfireg.h     |    8 +-
 usr.sbin/mfiutil/mfi_cmd.c    |    4 +-
 usr.sbin/mfiutil/mfi_config.c |  133 ++++++++++++++++-------
 usr.sbin/mfiutil/mfi_drive.c  |  124 ++++++++++++++++++++--
 usr.sbin/mfiutil/mfi_evt.c    |   25 ++++-
 usr.sbin/mfiutil/mfi_flash.c  |   34 ++++--
 usr.sbin/mfiutil/mfi_patrol.c |   30 ++++--
 usr.sbin/mfiutil/mfi_show.c   |  239 +++++++++++++++++++++++++++++++++++------
 usr.sbin/mfiutil/mfi_volume.c |   46 +++++++-
 usr.sbin/mfiutil/mfiutil.8    |   63 +++++++++---
 usr.sbin/mfiutil/mfiutil.c    |   16 +++-
 usr.sbin/mfiutil/mfiutil.h    |   10 ++-
 14 files changed, 627 insertions(+), 155 deletions(-)

diff --git a/sys/dev/raid/mfi/mfi.c b/sys/dev/raid/mfi/mfi.c
index 40d9d9c..210f5f8 100644
--- a/sys/dev/raid/mfi/mfi.c
+++ b/sys/dev/raid/mfi/mfi.c
@@ -49,7 +49,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/mfi/mfi.c,v 1.54 2009/12/07 21:24:07 jkim Exp $
+ * $FreeBSD: src/sys/dev/mfi/mfi.c,v 1.57 2011/07/14 20:20:33 jhb Exp $
  */
 
 #include "opt_mfi.h"
@@ -261,8 +261,12 @@ mfi_transition_firmware(struct mfi_softc *sc)
 		case MFI_FWSTATE_FLUSH_CACHE:
 			max_wait = 20;
 			break;
+		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
+			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
+			max_wait = 10;
+			break;
 		default:
-			device_printf(sc->mfi_dev,"Unknown firmware state %d\n",
+			device_printf(sc->mfi_dev,"Unknown firmware state %#x\n",
 			    fw_state);
 			return (ENXIO);
 		}
@@ -274,7 +278,7 @@ mfi_transition_firmware(struct mfi_softc *sc)
 				break;
 		}
 		if (fw_state == cur_state) {
-			device_printf(sc->mfi_dev, "firmware stuck in state "
+			device_printf(sc->mfi_dev, "Firmware stuck in state "
 			    "%#x\n", fw_state);
 			return (ENXIO);
 		}
@@ -485,7 +489,7 @@ mfi_attach(struct mfi_softc *sc)
 		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
 		return (EINVAL);
 	}
-	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 0,
+	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE,
 	    mfi_intr, sc, &sc->mfi_intr, NULL)) {
 		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
 		return (EINVAL);
@@ -792,7 +796,7 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
 
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = mfi_event_locale;
-	class_locale.members.class  = mfi_event_class;
+	class_locale.members.evt_class  = mfi_event_class;
 
 	if (seq_start == 0) {
 		error = mfi_get_log_state(sc, &log_state);
@@ -848,9 +852,7 @@ mfi_free(struct mfi_softc *sc)
 	struct mfi_command *cm;
 	int i;
 
-#if 0 /* XXX swildner */
-	callout_drain(&sc->mfi_watchdog_callout);
-#endif
+	callout_stop(&sc->mfi_watchdog_callout); /* XXX callout_drain() */
 
 	if (sc->mfi_cdev != NULL)
 		destroy_dev(sc->mfi_cdev);
@@ -1099,8 +1101,8 @@ mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
 {
 
 	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
-	    format_timestamp(detail->time), detail->class.members.locale,
-	    format_class(detail->class.members.class), detail->description);
+	    format_timestamp(detail->time), detail->evt_class.members.locale,
+	    format_class(detail->evt_class.members.evt_class), detail->description);
 }
 
 static int
@@ -1116,16 +1118,16 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
 	if (sc->mfi_aen_cm != NULL) {
 		prior_aen.word =
 		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
-		if (prior_aen.members.class <= current_aen.members.class &&
+		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
 		    !((prior_aen.members.locale & current_aen.members.locale)
 		    ^current_aen.members.locale)) {
 			return (0);
 		} else {
 			prior_aen.members.locale |= current_aen.members.locale;
-			if (prior_aen.members.class
-			    < current_aen.members.class)
-				current_aen.members.class =
-				    prior_aen.members.class;
+			if (prior_aen.members.evt_class
+			    < current_aen.members.evt_class)
+				current_aen.members.evt_class =
+				    prior_aen.members.evt_class;
 			mfi_abort(sc, sc->mfi_aen_cm);
 		}
 	}
@@ -1166,7 +1168,8 @@ mfi_aen_complete(struct mfi_command *cm)
 	if (sc->mfi_aen_cm == NULL)
 		return;
 
-	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
+	if (sc->mfi_aen_cm->cm_aen_abort ||
+	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
 		sc->mfi_aen_cm->cm_aen_abort = 0;
 		aborted = 1;
 	} else {
@@ -1216,7 +1219,7 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
 
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = mfi_event_locale;
-	class_locale.members.class  = mfi_event_class;
+	class_locale.members.evt_class  = mfi_event_class;
 
 	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
 		* (MAX_EVENTS - 1);
@@ -1428,7 +1431,7 @@ mfi_bio_complete(struct mfi_command *cm)
 	hdr = &cm->cm_frame->header;
 	sc = cm->cm_sc;
 
-	if ((hdr->cmd_status != 0) || (hdr->scsi_status != 0)) {
+	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
 		bp->b_flags |= B_ERROR;
 		bp->b_error = EIO;
 		device_printf(sc->mfi_dev, "I/O error, status= %d "
@@ -1572,7 +1575,7 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
 		cm->cm_timestamp = time_second;
 		mfi_enqueue_busy(cm);
 	} else {
-		hdr->cmd_status = 0xff;
+		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
 		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
 	}
 
@@ -1597,14 +1600,14 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
 		return (0);
 
 	/* This is a polled command, so busy-wait for it to complete. */
-	while (hdr->cmd_status == 0xff) {
+	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
 		DELAY(1000);
 		tm -= 1;
 		if (tm <= 0)
 			break;
 	}
 
-	if (hdr->cmd_status == 0xff) {
+	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
 		device_printf(sc->mfi_dev, "Frame %p timed out "
 			      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
 		return (ETIMEDOUT);
diff --git a/sys/dev/raid/mfi/mfi_cam.c b/sys/dev/raid/mfi/mfi_cam.c
index 56a68cf..abf7e9e 100644
--- a/sys/dev/raid/mfi/mfi_cam.c
+++ b/sys/dev/raid/mfi/mfi_cam.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.5 2010/12/06 17:02:56 jhb Exp $
+ * $FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.6 2011/06/28 08:36:48 kevlo Exp $
  */
 
 #include "opt_mfi.h"
@@ -52,10 +52,7 @@
 #include <bus/cam/scsi/scsi_all.h>
 #include <bus/cam/scsi/scsi_message.h>
 
-#include <sys/bus.h>
-#include <sys/conf.h>
 #include <machine/md_var.h>
-#include <sys/rman.h>
 
 #include <dev/raid/mfi/mfireg.h>
 #include <dev/raid/mfi/mfi_ioctl.h>
diff --git a/sys/dev/raid/mfi/mfireg.h b/sys/dev/raid/mfi/mfireg.h
index fa9e5a0..92b6f19 100644
--- a/sys/dev/raid/mfi/mfireg.h
+++ b/sys/dev/raid/mfi/mfireg.h
@@ -49,7 +49,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.14 2010/10/21 10:38:52 pluknet Exp $
+ * $FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.16 2011/07/14 20:20:33 jhb Exp $
  */
 
 #ifndef _MFIREG_H
@@ -111,6 +111,7 @@
 #define MFI_FWSTATE_WAIT_HANDSHAKE	0x60000000
 #define MFI_FWSTATE_FW_INIT_2		0x70000000
 #define MFI_FWSTATE_DEVICE_SCAN		0x80000000
+#define MFI_FWSTATE_BOOT_MESSAGE_PENDING	0x90000000
 #define MFI_FWSTATE_FLUSH_CACHE		0xa0000000
 #define MFI_FWSTATE_READY		0xb0000000
 #define MFI_FWSTATE_OPERATIONAL		0xc0000000
@@ -126,6 +127,7 @@
 #define MFI_FWINIT_READY	0x00000002 /* Move from operational to ready */
 #define MFI_FWINIT_MFIMODE	0x00000004 /* unknown */
 #define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */
+#define MFI_FWINIT_HOTPLUG	0x00000010
 
 /* MFI Commands */
 typedef enum {
@@ -718,7 +720,7 @@ union mfi_evt {
 	struct {
 		uint16_t	locale;
 		uint8_t		reserved;
-		int8_t		class;
+		int8_t		evt_class;
 	} members;
 	uint32_t		word;
 } __packed;
@@ -754,7 +756,7 @@ struct mfi_evt_detail {
 	uint32_t		seq;
 	uint32_t		time;
 	uint32_t		code;
-	union mfi_evt		class;
+	union mfi_evt		evt_class;
 	uint8_t			arg_type;
 	uint8_t			reserved1[15];
 
diff --git a/usr.sbin/mfiutil/mfi_cmd.c b/usr.sbin/mfiutil/mfi_cmd.c
index 155a8bf..e7c546b 100644
--- a/usr.sbin/mfiutil/mfi_cmd.c
+++ b/usr.sbin/mfiutil/mfi_cmd.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_cmd.c,v 1.2 2010/11/04 10:47:19 bcr Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_cmd.c,v 1.3 2011/02/25 13:59:59 pluknet Exp $
  */
 
 #define _KERNEL_STRUCTURES
@@ -318,7 +318,7 @@ mfi_display_progress(const char *label, struct mfi_progress *prog)
 
 	printf("%s: %.2f%% complete, after %ds", label,
 	    (float)prog->progress * 100 / 0xffff, prog->elapsed_seconds);
-	if (prog->elapsed_seconds > 10) {
+	if (prog->progress != 0 && prog->elapsed_seconds > 10) {
 		printf(" finished in ");
 		seconds = (0x10000 * (uint32_t)prog->elapsed_seconds) /
 		    prog->progress - prog->elapsed_seconds;
diff --git a/usr.sbin/mfiutil/mfi_config.c b/usr.sbin/mfiutil/mfi_config.c
index 07b926a..7b8621e 100644
--- a/usr.sbin/mfiutil/mfi_config.c
+++ b/usr.sbin/mfiutil/mfi_config.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_config.c,v 1.4 2010/11/19 15:39:59 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_config.c,v 1.6 2011/06/20 21:28:50 bz Exp $
  */
 
 #include <sys/param.h>
@@ -85,6 +85,7 @@ mfi_config_read(int fd, struct mfi_config_data **configp)
 {
 	struct mfi_config_data *config;
 	uint32_t config_size;
+	int error;
 
 	/*
 	 * Keep fetching the config in a loop until we have a large enough
@@ -97,8 +98,12 @@ fetch:
 	if (config == NULL)
 		return (-1);
 	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_READ, config,
-	    config_size, NULL, 0, NULL) < 0)
+	    config_size, NULL, 0, NULL) < 0) {
+		error = errno;
+		free(config);
+		errno = error;
 		return (-1);
+	}
 
 	if (config->size > config_size) {
 		config_size = config->size;
@@ -162,12 +167,14 @@ clear_config(int ac, char **av)
 	if (!mfi_reconfig_supported()) {
 		warnx("The current mfi(4) driver does not support "
 		    "configuration changes.");
+		close(fd);
 		return (EOPNOTSUPP);
 	}
 
 	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
 		error = errno;
 		warn("Failed to get volume list");
+		close(fd);
 		return (error);
 	}
 
@@ -175,6 +182,7 @@ clear_config(int ac, char **av)
 		if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) {
 			warnx("Volume %s is busy and cannot be deleted",
 			    mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
+			close(fd);
 			return (EBUSY);
 		}
 	}
@@ -185,12 +193,14 @@ clear_config(int ac, char **av)
 	ch = getchar();
 	if (ch != 'y' && ch != 'Y') {
 		printf("\nAborting\n");
+		close(fd);
 		return (0);
 	}
 
 	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to clear configuration");
+		close(fd);
 		return (error);
 	}
 
@@ -336,17 +346,21 @@ parse_array(int fd, int raid_type, char *array_str, struct array_info *info)
 	for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL;
 	     pinfo++) {
 		error = mfi_lookup_drive(fd, cp, &device_id);
-		if (error)
+		if (error) {
+			free(info->drives);
 			return (error);
+		}
 
 		if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) {
 			error = errno;
 			warn("Failed to fetch drive info for drive %s", cp);
+			free(info->drives);
 			return (error);
 		}
 
 		if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
 			warnx("Drive %u is not available", device_id);
+			free(info->drives);
 			return (EINVAL);
 		}
 	}
@@ -405,8 +419,10 @@ build_array(int fd, char *arrayp, struct array_info *array_info,
 	ar->array_ref = find_next_array(state);
 	for (i = 0; i < array_info->drive_count; i++) {
 		if (verbose)
-			printf("Adding drive %u to array %u\n",
+			printf("Adding drive %s to array %u\n",
+			    mfi_drive_name(NULL,
 			    array_info->drives[i].ref.v.device_id,
+			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS),
 			    ar->array_ref);
 		if (ar->size > array_info->drives[i].coerced_size)
 			ar->size = array_info->drives[i].coerced_size;
@@ -551,6 +567,11 @@ create_volume(int ac, char **av)
 		return (EINVAL);
 	}
 
+	bzero(&state, sizeof(state));
+	config = NULL;
+	arrays = NULL;
+	narrays = 0;
+	error = 0;
 
 	fd = mfi_open(mfi_unit);
 	if (fd < 0) {
@@ -562,7 +583,8 @@ create_volume(int ac, char **av)
 	if (!mfi_reconfig_supported()) {
 		warnx("The current mfi(4) driver does not support "
 		    "configuration changes.");
-		return (EOPNOTSUPP);
+		error = EOPNOTSUPP;
+		goto error;
 	}
 
 	/* Lookup the RAID type first. */
@@ -575,7 +597,8 @@ create_volume(int ac, char **av)
 
 	if (raid_type == -1) {
 		warnx("Unknown or unsupported volume type %s", av[1]);
-		return (EINVAL);
+		error = EINVAL;
+		goto error;
 	}
 
 	/* Parse any options. */
@@ -603,7 +626,8 @@ create_volume(int ac, char **av)
 			break;
 		case '?':
 		default:
-			return (EINVAL);
+			error = EINVAL;
+			goto error;
 		}
 	}
 	ac -= optind;
@@ -613,7 +637,8 @@ create_volume(int ac, char **av)
 	narrays = ac;
 	if (narrays == 0) {
 		warnx("At least one drive list is required");
-		return (EINVAL);
+		error = EINVAL;
+		goto error;
 	}
 	switch (raid_type) {
 	case RT_RAID0:
@@ -623,7 +648,8 @@ create_volume(int ac, char **av)
 	case RT_CONCAT:
 		if (narrays != 1) {
 			warnx("Only one drive list can be specified");
-			return (EINVAL);
+			error = EINVAL;
+			goto error;
 		}
 		break;
 	case RT_RAID10:
@@ -632,24 +658,27 @@ create_volume(int ac, char **av)
 		if (narrays < 1) {
 			warnx("RAID10, RAID50, and RAID60 require at least "
 			    "two drive lists");
-			return (EINVAL);
+			error = EINVAL;
+			goto error;
 		}
 		if (narrays > MFI_MAX_SPAN_DEPTH) {
 			warnx("Volume spans more than %d arrays",
 			    MFI_MAX_SPAN_DEPTH);
-			return (EINVAL);
+			error = EINVAL;
+			goto error;
 		}
 		break;
 	}
 	arrays = calloc(narrays, sizeof(*arrays));
 	if (arrays == NULL) {
 		warnx("malloc failed");
-		return (ENOMEM);
+		error = ENOMEM;
+		goto error;
 	}
 	for (i = 0; i < narrays; i++) {
 		error = parse_array(fd, raid_type, av[i], &arrays[i]);
 		if (error)
-			return (error);
+			goto error;
 	}
 
 	switch (raid_type) {
@@ -660,7 +689,8 @@ create_volume(int ac, char **av)
 			if (arrays[i].drive_count != arrays[0].drive_count) {
 				warnx("All arrays must contain the same "
 				    "number of drives");
-				return (EINVAL);
+				error = EINVAL;
+				goto error;
 			}
 		}
 		break;
@@ -673,7 +703,7 @@ create_volume(int ac, char **av)
 	if (mfi_config_read(fd, &config) < 0) {
 		error = errno;
 		warn("Failed to read configuration");
-		return (error);
+		goto error;
 	}
 	p = (char *)config->array;
 	state.array_ref = 0xffff;
@@ -683,7 +713,8 @@ create_volume(int ac, char **av)
 		state.arrays = calloc(config->array_count, sizeof(int));
 		if (state.arrays == NULL) {
 			warnx("malloc failed");
-			return (ENOMEM);
+			error = ENOMEM;
+			goto error;
 		}
 		for (i = 0; i < config->array_count; i++) {
 			ar = (struct mfi_array *)p;
@@ -699,7 +730,8 @@ create_volume(int ac, char **av)
 		state.volumes = calloc(config->log_drv_count, sizeof(int));
 		if (state.volumes == NULL) {
 			warnx("malloc failed");
-			return (ENOMEM);
+			error = ENOMEM;
+			goto error;
 		}
 		for (i = 0; i < config->log_drv_count; i++) {
 			ld = (struct mfi_ld_config *)p;
@@ -739,7 +771,8 @@ create_volume(int ac, char **av)
 	config = calloc(1, config_size);
 	if (config == NULL) {
 		warnx("malloc failed");
-		return (ENOMEM);
+		error = ENOMEM;
+		goto error;
 	}
 	config->size = config_size;
 	config->array_count = narrays;
@@ -776,21 +809,20 @@ create_volume(int ac, char **av)
 	    NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to add volume");
-		return (error);
+		/* FALLTHROUGH */
 	}
 
+error:
 	/* Clean up. */
 	free(config);
-	if (state.log_drv_count > 0)
-		free(state.volumes);
-	if (state.array_count > 0)
-		free(state.arrays);
+	free(state.volumes);
+	free(state.arrays);
 	for (i = 0; i < narrays; i++)
 		free(arrays[i].drives);
 	free(arrays);
 	close(fd);
 
-	return (0);
+	return (error);
 }
 MFI_COMMAND(top, create, create_volume);
 
@@ -831,24 +863,28 @@ delete_volume(int ac, char **av)
 	if (!mfi_reconfig_supported()) {
 		warnx("The current mfi(4) driver does not support "
 		    "configuration changes.");
+		close(fd);
 		return (EOPNOTSUPP);
 	}
 
 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
 		error = errno;
 		warn("Invalid volume %s", av[1]);
+		close(fd);
 		return (error);
 	}
 
 	if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to get info for volume %d", target_id);
+		close(fd);
 		return (error);
 	}
 
 	if (mfi_volume_busy(fd, target_id)) {
 		warnx("Volume %s is busy and cannot be deleted",
 		    mfi_volume_name(fd, target_id));
+		close(fd);
 		return (EBUSY);
 	}
 
@@ -857,6 +893,7 @@ delete_volume(int ac, char **av)
 	    sizeof(mbox), NULL) < 0) {
 		error = errno;
 		warn("Failed to delete volume");
+		close(fd);
 		return (error);
 	}
 
@@ -891,40 +928,44 @@ add_spare(int ac, char **av)
 		return (error);
 	}
 
+	config = NULL;
+	spare = NULL;
 	error = mfi_lookup_drive(fd, av[1], &device_id);
 	if (error)
-		return (error);
+		goto error;
 
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch drive info");
-		return (error);
+		goto error;
 	}
 
 	if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
 		warnx("Drive %u is not available", device_id);
-		return (EINVAL);
+		error = EINVAL;
+		goto error;
 	}
 
 	if (ac > 2) {
 		if (mfi_lookup_volume(fd, av[2], &target_id) < 0) {
 			error = errno;
 			warn("Invalid volume %s", av[2]);
-			return (error);
+			goto error;
 		}
 	}
 
 	if (mfi_config_read(fd, &config) < 0) {
 		error = errno;
 		warn("Failed to read configuration");
-		return (error);
+		goto error;
 	}
 
 	spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) *
 	    config->array_count);
 	if (spare == NULL) {
 		warnx("malloc failed");
-		return (ENOMEM);
+		error = ENOMEM;
+		goto error;
 	}
 	bzero(spare, sizeof(struct mfi_spare));
 	spare->ref = info.ref;
@@ -937,7 +978,8 @@ add_spare(int ac, char **av)
 			if (ar->size > info.coerced_size) {
 				warnx("Spare isn't large enough for array %u",
 				    ar->array_ref);
-				return (EINVAL);
+				error = EINVAL;
+				goto error;
 			}
 			p += config->array_size;
 		}
@@ -950,7 +992,8 @@ add_spare(int ac, char **av)
 		ld = mfi_config_lookup_volume(config, target_id);
 		if (ld == NULL) {
 			warnx("Did not find volume %d", target_id);
-			return (EINVAL);
+			error = EINVAL;
+			goto error;
 		}
 
 		spare->spare_type |= MFI_SPARE_DEDICATED;
@@ -960,29 +1003,33 @@ add_spare(int ac, char **av)
 			    ld->span[i].array_ref);
 			if (ar == NULL) {
 				warnx("Missing array; inconsistent config?");
-				return (ENXIO);
+				error = ENXIO;
+				goto error;
 			}
 			if (ar->size > info.coerced_size) {
 				warnx("Spare isn't large enough for array %u",
 				    ar->array_ref);
-				return (EINVAL);
+				error = EINVAL;
+				goto error;
 			}
 			spare->array_ref[i] = ar->array_ref;
 		}
 	}
-	free(config);
 
 	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare,
 	    sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count,
 	    NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to assign spare");
-		return (error);
+		/* FALLTHROUGH. */
 	}
 
+error:
+	free(spare);
+	free(config);
 	close(fd);
 
-	return (0);
+	return (error);
 }
 MFI_COMMAND(top, add, add_spare);
 
@@ -1007,18 +1054,22 @@ remove_spare(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 
 	if (info.fw_state != MFI_PD_STATE_HOT_SPARE) {
 		warnx("Drive %u is not a hot spare", device_id);
+		close(fd);
 		return (EINVAL);
 	}
 
@@ -1027,6 +1078,7 @@ remove_spare(int ac, char **av)
 	    sizeof(mbox), NULL) < 0) {
 		error = errno;
 		warn("Failed to delete spare");
+		close(fd);
 		return (error);
 	}
 
@@ -1151,6 +1203,7 @@ debug_config(int ac, char **av)
 	if (mfi_config_read(fd, &config) < 0) {
 		error = errno;
 		warn("Failed to get config");
+		close(fd);
 		return (error);
 	}
 
@@ -1190,17 +1243,21 @@ dump(int ac, char **av)
 		warn("Failed to read debug command");
 		if (error == ENOENT)
 			error = EOPNOTSUPP;
+		close(fd);
 		return (error);
 	}
 
 	config = malloc(len);
 	if (config == NULL) {
 		warnx("malloc failed");
+		close(fd);
 		return (ENOMEM);
 	}
 	if (sysctlbyname(buf, config, &len, NULL, 0) < 0) {
 		error = errno;
 		warn("Failed to read debug command");
+		free(config);
+		close(fd);
 		return (error);
 	}
 	dump_config(fd, config);
diff --git a/usr.sbin/mfiutil/mfi_drive.c b/usr.sbin/mfiutil/mfi_drive.c
index 33c1c38..fe98206 100644
--- a/usr.sbin/mfiutil/mfi_drive.c
+++ b/usr.sbin/mfiutil/mfi_drive.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_drive.c,v 1.4 2010/10/26 19:11:09 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_drive.c,v 1.6 2011/06/20 21:28:50 bz Exp $
  */
 
 #include <sys/types.h>
@@ -45,6 +45,87 @@
 
 MFI_TABLE(top, drive);
 
+/*
+ * Print the name of a drive either by drive number as %2u or by enclosure:slot
+ * as Exx:Sxx (or both).  Use default unless command line options override it
+ * and the command allows this (which we usually do unless we already print
+ * both).  We prefer pinfo if given, otherwise try to look it up by device_id.
+ */
+const char *
+mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id, uint32_t def)
+{
+	struct mfi_pd_info info;
+	static char buf[16];
+	char *p;
+	int error, fd, len;
+
+	if ((def & MFI_DNAME_HONOR_OPTS) != 0 &&
+	    (mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) != 0)
+		def = mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID);
+
+	buf[0] = '\0';
+	if (pinfo == NULL && def & MFI_DNAME_ES) {
+		/* Fallback in case of error, just ignore flags. */
+		if (device_id == 0xffff)
+			snprintf(buf, sizeof(buf), "MISSING");
+		else
+			snprintf(buf, sizeof(buf), "%2u", device_id);
+
+		fd = mfi_open(mfi_unit);
+		if (fd < 0) {
+			warn("mfi_open");
+			return (buf);
+		}
+
+		/* Get the info for this drive. */
+		if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
+			warn("Failed to fetch info for drive %2u", device_id);
+			close(fd);
+			return (buf);
+		}
+
+		close(fd);
+		pinfo = &info;
+	}
+
+	p = buf;
+	len = sizeof(buf);
+	if (def & MFI_DNAME_DEVICE_ID) {
+		if (device_id == 0xffff)
+			error = snprintf(p, len, "MISSING");
+		else
+			error = snprintf(p, len, "%2u", device_id);
+		if (error >= 0) {
+			p += error;
+			len -= error;
+		}
+	}
+	if ((def & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) ==
+	    (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID) && len >= 2) {
+		*p++ = ' ';
+		len--;
+		*p = '\0';
+		len--;
+	}
+	if (def & MFI_DNAME_ES) {
+		if (pinfo->encl_device_id == 0xffff)
+			error = snprintf(p, len, "S%u",
+			    pinfo->slot_number);
+		else if (pinfo->encl_device_id == pinfo->ref.v.device_id)
+			error = snprintf(p, len, "E%u",
+			    pinfo->encl_index);
+		else
+			error = snprintf(p, len, "E%u:S%u",
+			    pinfo->encl_index, pinfo->slot_number);
+		if (error >= 0) {
+			p += error;
+			len -= error;
+		}
+	}
+
+	return (buf);
+}
+
 const char *
 mfi_pdstate(enum mfi_pd_state state)
 {
@@ -310,19 +391,23 @@ drive_set_state(char *drive, uint16_t new_state)
 	}
 
 	error = mfi_lookup_drive(fd, drive, &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 
 	/* Try to change the state. */
 	if (info.fw_state == new_state) {
 		warnx("Drive %u is already in the desired state", device_id);
+		close(fd);
 		return (EINVAL);
 	}
 
@@ -334,6 +419,7 @@ drive_set_state(char *drive, uint16_t new_state)
 		error = errno;
 		warn("Failed to set drive %u to %s", device_id,
 		    mfi_pdstate(new_state));
+		close(fd);
 		return (error);
 	}
 
@@ -406,19 +492,23 @@ start_rebuild(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 
 	/* Check the state, must be REBUILD. */
 	if (info.fw_state != MFI_PD_STATE_REBUILD) {
 		warnx("Drive %d is not in the REBUILD state", device_id);
+		close(fd);
 		return (EINVAL);
 	}
 
@@ -428,6 +518,7 @@ start_rebuild(int ac, char **av)
 	    NULL) < 0) {
 		error = errno;
 		warn("Failed to start rebuild on drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 	close(fd);
@@ -458,19 +549,23 @@ abort_rebuild(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 
 	/* Check the state, must be REBUILD. */
 	if (info.fw_state != MFI_PD_STATE_REBUILD) {
 		warn("Drive %d is not in the REBUILD state", device_id);
+		close(fd);
 		return (EINVAL);
 	}
 
@@ -480,6 +575,7 @@ abort_rebuild(int ac, char **av)
 	    NULL) < 0) {
 		error = errno;
 		warn("Failed to abort rebuild on drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 	close(fd);
@@ -509,13 +605,16 @@ drive_progress(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 	close(fd);
@@ -529,7 +628,9 @@ drive_progress(int ac, char **av)
 		mfi_display_progress("Clear", &info.prog_info.clear);
 	if ((info.prog_info.active & (MFI_PD_PROGRESS_REBUILD |
 	    MFI_PD_PROGRESS_PATROL | MFI_PD_PROGRESS_CLEAR)) == 0)
-		printf("No activity in progress for drive %u.\n", device_id);
+		printf("No activity in progress for drive %s.\n",
+		mfi_drive_name(NULL, device_id,
+		    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
 
 	return (0);
 }
@@ -570,13 +671,16 @@ drive_clear(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 	/* Get the info for this drive. */
 	if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to fetch info for drive %u", device_id);
+		close(fd);
 		return (error);
 	}
 
@@ -586,6 +690,7 @@ drive_clear(int ac, char **av)
 		warn("Failed to %s clear on drive %u",
 		    opcode == MFI_DCMD_PD_CLEAR_START ? "start" : "stop",
 		    device_id);
+		close(fd);
 		return (error);
 	}
 
@@ -626,8 +731,10 @@ drive_locate(int ac, char **av)
 	}
 
 	error = mfi_lookup_drive(fd, av[1], &device_id);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 
 
 	mbox_store_device_id(&mbox[0], device_id);
@@ -638,6 +745,7 @@ drive_locate(int ac, char **av)
 		warn("Failed to %s locate on drive %u",
 		    opcode == MFI_DCMD_PD_LOCATE_START ? "start" : "stop",
 		    device_id);
+		close(fd);
 		return (error);
 	}
 	close(fd);
diff --git a/usr.sbin/mfiutil/mfi_evt.c b/usr.sbin/mfiutil/mfi_evt.c
index 9ba397e..6696d8d 100644
--- a/usr.sbin/mfiutil/mfi_evt.c
+++ b/usr.sbin/mfiutil/mfi_evt.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_evt.c,v 1.3 2010/11/19 15:39:59 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_evt.c,v 1.5 2011/06/09 19:52:28 bz Exp $
  */
 
 #include <sys/types.h>
@@ -83,6 +83,7 @@ show_logstate(int ac, char **av)
 	if (mfi_event_get_info(fd, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to get event log info");
+		close(fd);
 		return (error);
 	}
 
@@ -362,8 +363,8 @@ mfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose)
 {
 
 	printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time),
-	    format_locale(detail->class.members.locale),
-	    format_class(detail->class.members.class));
+	    format_locale(detail->evt_class.members.locale),
+	    format_class(detail->evt_class.members.evt_class));
 	switch (detail->arg_type) {
 	case MR_EVT_ARGS_NONE:
 		break;
@@ -550,6 +551,7 @@ show_events(int ac, char **av)
 	if (mfi_event_get_info(fd, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to get event log info");
+		close(fd);
 		return (error);
 	}
 
@@ -557,7 +559,7 @@ show_events(int ac, char **av)
 	num_events = 15;
 	filter.members.reserved = 0;
 	filter.members.locale = MFI_EVT_LOCALE_ALL;
-	filter.members.class = MFI_EVT_CLASS_WARNING;
+	filter.members.evt_class = MFI_EVT_CLASS_WARNING;
 	start = info.boot_seq_num;
 	stop = info.newest_seq_num;
 	verbose = 0;
@@ -567,9 +569,10 @@ show_events(int ac, char **av)
 	while ((ch = getopt(ac, av, "c:l:n:v")) != -1) {
 		switch (ch) {
 		case 'c':
-			if (parse_class(optarg, &filter.members.class) < 0) {
+			if (parse_class(optarg, &filter.members.evt_class) < 0) {
 				error = errno;
 				warn("Error parsing event class");
+				close(fd);
 				return (error);
 			}
 			break;
@@ -577,6 +580,7 @@ show_events(int ac, char **av)
 			if (parse_locale(optarg, &filter.members.locale) < 0) {
 				error = errno;
 				warn("Error parsing event locale");
+				close(fd);
 				return (error);
 			}
 			break;
@@ -584,6 +588,7 @@ show_events(int ac, char **av)
 			val = strtol(optarg, &cp, 0);
 			if (*cp != '\0' || val <= 0) {
 				warnx("Invalid event count");
+				close(fd);
 				return (EINVAL);
 			}
 			num_events = val;
@@ -593,6 +598,7 @@ show_events(int ac, char **av)
 			break;
 		case '?':
 		default:
+			close(fd);
 			return (EINVAL);
 		}
 	}
@@ -604,28 +610,33 @@ show_events(int ac, char **av)
 	    (num_events - 1);
 	if (size > getpagesize()) {
 		warnx("Event count is too high");
+		close(fd);
 		return (EINVAL);
 	}
 
 	/* Handle optional start and stop sequence numbers. */
 	if (ac > 2) {
 		warnx("show events: extra arguments");
+		close(fd);
 		return (EINVAL);
 	}
 	if (ac > 0 && parse_seq(&info, av[0], &start) < 0) {
 		error = errno;
 		warn("Error parsing starting sequence number");
+		close(fd);
 		return (error);
 	}
 	if (ac > 1 && parse_seq(&info, av[1], &stop) < 0) {
 		error = errno;
 		warn("Error parsing ending sequence number");
+		close(fd);
 		return (error);
 	}
 
 	list = malloc(size);
 	if (list == NULL) {
 		warnx("malloc failed");
+		close(fd);
 		return (ENOMEM);
 	}
 	for (seq = start;;) {
@@ -633,6 +644,8 @@ show_events(int ac, char **av)
 		    &status) < 0) {
 			error = errno;
 			warn("Failed to fetch events");
+			free(list);
+			close(fd);
 			return (error);
 		}
 		if (status == MFI_STAT_NOT_FOUND) {
@@ -642,6 +655,8 @@ show_events(int ac, char **av)
 		}
 		if (status != MFI_STAT_OK) {
 			warnx("Error fetching events: %s", mfi_status(status));
+			free(list);
+			close(fd);
 			return (EIO);
 		}
 
diff --git a/usr.sbin/mfiutil/mfi_flash.c b/usr.sbin/mfiutil/mfi_flash.c
index 6f08260..1940b10 100644
--- a/usr.sbin/mfiutil/mfi_flash.c
+++ b/usr.sbin/mfiutil/mfi_flash.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_flash.c,v 1.3 2010/11/19 15:39:59 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_flash.c,v 1.4 2011/06/09 19:52:28 bz Exp $
  */
 
 #include <sys/param.h>
@@ -136,21 +136,25 @@ flash_adapter(int ac, char **av)
 		return (error);
 	}
 
+	buf = NULL;
+	fd = -1;
+
 	if (fstat(flash, &sb) < 0) {
 		error = errno;
 		warn("fstat(%s)", av[1]);
-		return (error);
+		goto error;
 	}
 	if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
 		warnx("Invalid flash file size");
-		return (EINVAL);
+		error = EINVAL;
+		goto error;
 	}
 
 	fd = mfi_open(mfi_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mfi_open");
-		return (error);
+		goto error;
 	}
 
 	/* First, ask the firmware to allocate space for the flash file. */
@@ -158,14 +162,16 @@ flash_adapter(int ac, char **av)
 	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
 	if (status != MFI_STAT_OK) {
 		warnx("Failed to alloc flash memory: %s", mfi_status(status));
-		return (EIO);
+		error = EIO;
+		goto error;
 	}
 
 	/* Upload the file 64k at a time. */
 	buf = malloc(FLASH_BUF_SIZE);
 	if (buf == NULL) {
 		warnx("malloc failed");
-		return (ENOMEM);
+		error = ENOMEM;
+		goto error;
 	}
 	offset = 0;
 	while (sb.st_size > 0) {
@@ -174,7 +180,8 @@ flash_adapter(int ac, char **av)
 			warnx("Bad read from flash file");
 			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
 			    NULL, 0, NULL);
-			return (ENXIO);
+			error = ENXIO;
+			goto error;
 		}
 
 		mbox_store_word(mbox, offset);
@@ -184,12 +191,12 @@ flash_adapter(int ac, char **av)
 			warnx("Flash download failed: %s", mfi_status(status));
 			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
 			    NULL, 0, NULL);
-			return (ENXIO);
+			error = ENXIO;
+			goto error;
 		}
 		sb.st_size -= nread;
 		offset += nread;
 	}
-	close(flash);
 
 	/* Kick off the flash. */
 	printf("WARNING: Firmware flash in progress, do not reboot machine... ");
@@ -198,12 +205,17 @@ flash_adapter(int ac, char **av)
 	    NULL, 0, &status);
 	if (status != MFI_STAT_OK) {
 		printf("failed:\n\t%s\n", mfi_status(status));
-		return (ENXIO);
+		error = ENXIO;
+		goto error;
 	}
 	printf("finished\n");
 	error = display_pending_firmware(fd);
 
-	close(fd);
+error:
+	free(buf);
+	if (fd >= 0)
+		close(fd);
+	close(flash);
 
 	return (error);
 }
diff --git a/usr.sbin/mfiutil/mfi_patrol.c b/usr.sbin/mfiutil/mfi_patrol.c
index d3172e5..01bcf2b 100644
--- a/usr.sbin/mfiutil/mfi_patrol.c
+++ b/usr.sbin/mfiutil/mfi_patrol.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_patrol.c,v 1.2 2010/10/26 19:11:09 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_patrol.c,v 1.5 2011/06/20 21:28:50 bz Exp $
  */
 
 #include <sys/types.h>
@@ -80,7 +80,7 @@ show_patrol(int ac, char **av)
 	struct mfi_pr_status status;
 	struct mfi_pd_list *list;
 	struct mfi_pd_info info;
-	char label[16];
+	char label[24];
 	time_t now;
 	uint32_t at;
 	int error, fd;
@@ -96,8 +96,10 @@ show_patrol(int ac, char **av)
 	time(&now);
 	mfi_get_time(fd, &at);
 	error = patrol_get_props(fd, &prop);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 	printf("Operation Mode: ");
 	switch (prop.op_mode) {
 	case MFI_PR_OPMODE_AUTO:
@@ -128,6 +130,7 @@ show_patrol(int ac, char **av)
 	    sizeof(status), NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to get patrol read properties");
+		close(fd);
 		return (error);
 	}
 	printf("Runs Completed: %u\n", status.num_iteration);
@@ -153,6 +156,7 @@ show_patrol(int ac, char **av)
 		if (mfi_pd_get_list(fd, &list, NULL) < 0) {
 			error = errno;
 			warn("Failed to get drive list");
+			close(fd);
 			return (error);
 		}
 
@@ -165,15 +169,20 @@ show_patrol(int ac, char **av)
 				error = errno;
 				warn("Failed to fetch info for drive %u",
 				    list->addr[i].device_id);
+				free(list);
+				close(fd);
 				return (error);
 			}
 			if (info.prog_info.active & MFI_PD_PROGRESS_PATROL) {
-				snprintf(label, sizeof(label), "    Drive %u",
-				    list->addr[i].device_id);
+				snprintf(label, sizeof(label), "    Drive %s",
+				    mfi_drive_name(NULL,
+				    list->addr[i].device_id,
+				    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
 				mfi_display_progress(label,
 				    &info.prog_info.patrol);
 			}
 		}
+		free(list);
 	}
 
 	close(fd);
@@ -198,6 +207,7 @@ start_patrol(int ac, char **av)
 	    0) {
 		error = errno;
 		warn("Failed to start patrol read");
+		close(fd);
 		return (error);
 	}
 
@@ -223,6 +233,7 @@ stop_patrol(int ac, char **av)
 	    0) {
 		error = errno;
 		warn("Failed to stop patrol read");
+		close(fd);
 		return (error);
 	}
 
@@ -289,8 +300,10 @@ patrol_config(int ac, char **av)
 	}
 
 	error = patrol_get_props(fd, &prop);
-	if (error)
+	if (error) {
+		close(fd);
 		return (error);
+	}
 	prop.op_mode = op_mode;
 	if (op_mode == MFI_PR_OPMODE_AUTO) {
 		if (ac > 2)
@@ -298,8 +311,10 @@ patrol_config(int ac, char **av)
 		if (ac > 3) {
 			time(&now);
 			mfi_get_time(fd, &at);
-			if (at == 0)
+			if (at == 0) {
+				close(fd);
 				return (ENXIO);
+			}
 			prop.next_exec = at + next_exec;
 			printf("Starting next patrol read at %s",
 			    adapter_time(now, at, prop.next_exec));
@@ -309,6 +324,7 @@ patrol_config(int ac, char **av)
 	    sizeof(prop), NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to set patrol read properties");
+		close(fd);
 		return (error);
 	}
 
diff --git a/usr.sbin/mfiutil/mfi_show.c b/usr.sbin/mfiutil/mfi_show.c
index c74e5da..0818514 100644
--- a/usr.sbin/mfiutil/mfi_show.c
+++ b/usr.sbin/mfiutil/mfi_show.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_show.c,v 1.2 2010/10/26 19:11:09 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_show.c,v 1.8 2011/07/29 20:24:04 jhb Exp $
  */
 
 #include <sys/types.h>
@@ -71,6 +71,7 @@ show_adapter(int ac, char **av)
 	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to get controller info");
+		close(fd);
 		return (error);
 	}
 	printf("mfi%d Adapter:\n", mfi_unit);
@@ -138,8 +139,9 @@ show_battery(int ac, char **av)
 {
 	struct mfi_bbu_capacity_info cap;
 	struct mfi_bbu_design_info design;
+	struct mfi_bbu_status stat;
 	uint8_t status;
-	int error, fd;
+	int comma, error, fd;
 
 	if (ac != 1) {
 		warnx("show battery: extra arguments");
@@ -157,10 +159,12 @@ show_battery(int ac, char **av)
 	    sizeof(cap), NULL, 0, &status) < 0) {
 		if (status == MFI_STAT_NO_HW_PRESENT) {
 			printf("mfi%d: No battery present\n", mfi_unit);
+			close(fd);
 			return (0);
 		}
 		error = errno;
 		warn("Failed to get capacity info");
+		close(fd);
 		return (error);
 	}
 
@@ -168,19 +172,63 @@ show_battery(int ac, char **av)
 	    sizeof(design), NULL, 0, NULL) < 0) {
 		error = errno;
 		warn("Failed to get design info");
+		close(fd);
+		return (error);
+	}
+
+	if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat),
+	    NULL, 0, NULL) < 0) {
+		error = errno;
+		warn("Failed to get status");
+		close(fd);
 		return (error);
 	}
 
 	printf("mfi%d: Battery State:\n", mfi_unit);
-	printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f,
+	printf("     Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f,
 	    design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff);
-	printf("    Serial Number: %d\n", design.serial_number);
-	printf("     Manufacturer: %s\n", design.mfg_name);
-	printf("            Model: %s\n", design.device_name);
-	printf("        Chemistry: %s\n", design.device_chemistry);
-	printf("  Design Capacity: %d mAh\n", design.design_capacity);
-	printf("   Design Voltage: %d mV\n", design.design_voltage);
-	printf("   Current Charge: %d%%\n", cap.relative_charge);
+	printf("        Serial Number: %d\n", design.serial_number);
+	printf("         Manufacturer: %s\n", design.mfg_name);
+	printf("                Model: %s\n", design.device_name);
+	printf("            Chemistry: %s\n", design.device_chemistry);
+	printf("      Design Capacity: %d mAh\n", design.design_capacity);
+	printf(" Full Charge Capacity: %d mAh\n", cap.full_charge_capacity);
+	printf("     Current Capacity: %d mAh\n", cap.remaining_capacity);
+	printf("        Charge Cycles: %d\n", cap.cycle_count);
+	printf("       Current Charge: %d%%\n", cap.relative_charge);
+	printf("       Design Voltage: %d mV\n", design.design_voltage);
+	printf("      Current Voltage: %d mV\n", stat.voltage);
+	printf("          Temperature: %d C\n", stat.temperature);
+	printf("               Status:");
+	comma = 0;
+	if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) {
+		printf(" PACK_MISSING");
+		comma = 1;
+	}
+	if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) {
+		printf("%s VOLTAGE_LOW", comma ? "," : "");
+		comma = 1;
+	}
+	if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) {
+		printf("%s TEMPERATURE_HIGH", comma ? "," : "");
+		comma = 1;
+	}
+	if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) {
+		printf("%s CHARGING", comma ? "," : "");
+		comma = 1;
+	}
+	if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) {
+		printf("%s DISCHARGING", comma ? "," : "");
+	}
+	if (!comma)
+		printf(" normal");
+	printf("\n");
+	switch (stat.battery_type) {
+	case MFI_BBU_TYPE_BBU:
+		printf("      State of Health: %s\n",
+		    stat.detail.bbu.is_SOH_good ? "good" : "bad");
+		break;
+	}
 
 	close(fd);
 
@@ -210,7 +258,7 @@ print_ld(struct mfi_ld_info *info, int state_len)
 }
 
 static void
-print_pd(struct mfi_pd_info *info, int state_len, int location)
+print_pd(struct mfi_pd_info *info, int state_len)
 {
 	const char *s;
 	char buf[6];
@@ -225,15 +273,6 @@ print_pd(struct mfi_pd_info *info, int state_len, int location)
 	s = mfi_pd_inq_string(info);
 	if (s != NULL)
 		printf(" %s", s);
-	if (!location)
-		return;
-	if (info->encl_device_id == 0xffff)
-		printf(" slot %d", info->slot_number);
-	else if (info->encl_device_id == info->ref.v.device_id)
-		printf(" enclosure %d", info->encl_index);
-	else
-		printf(" enclosure %d, slot %d", info->encl_index,
-		    info->slot_number);
 }
 
 static int
@@ -265,6 +304,7 @@ show_config(int ac, char **av)
 	if (mfi_config_read(fd, &config) < 0) {
 		error = errno;
 		warn("Failed to get config");
+		close(fd);
 		return (error);
 	}
 
@@ -280,16 +320,16 @@ show_config(int ac, char **av)
 		    ar->num_drives);
 		for (j = 0; j < ar->num_drives; j++) {
 			device_id = ar->pd[j].ref.v.device_id;
-			if (device_id == 0xffff)
-				printf("        drive MISSING\n");
-			else {
-				printf("        drive %u ", device_id);
+			printf("        drive %s ", mfi_drive_name(NULL,
+			    device_id,
+			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
+			if (device_id != 0xffff) {
 				if (mfi_pd_get_info(fd, device_id, &pinfo,
 				    NULL) < 0)
 					printf("%s",
 					    mfi_pdstate(ar->pd[j].fw_state));
 				else
-					print_pd(&pinfo, -1, 1);
+					print_pd(&pinfo, -1);
 				printf("\n");
 			}
 		}
@@ -318,13 +358,14 @@ show_config(int ac, char **av)
 
 	for (i = 0; i < config->spares_count; i++) {
 		sp = (struct mfi_spare *)p;
-		printf("    %s spare %u ",
+		printf("    %s spare %s ",
 		    sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
-		    "global", sp->ref.v.device_id);
+		    "global", mfi_drive_name(NULL, sp->ref.v.device_id,
+		    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
 		if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0)
 			printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
 		else
-			print_pd(&pinfo, -1, 1);
+			print_pd(&pinfo, -1);
 		if (sp->spare_type & MFI_SPARE_DEDICATED) {
 			printf(" backs:\n");
 			for (j = 0; j < sp->array_count; j++)
@@ -333,6 +374,7 @@ show_config(int ac, char **av)
 			printf("\n");
 		p += config->spares_size;
 	}
+	free(config);
 	close(fd);
 
 	return (0);
@@ -363,6 +405,7 @@ show_volumes(int ac, char **av)
 	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
 		error = errno;
 		warn("Failed to get volume list");
+		close(fd);
 		return (error);
 	}
 
@@ -388,6 +431,7 @@ show_volumes(int ac, char **av)
 			error = errno;
 			warn("Failed to get info for volume %d",
 			    list.ld_list[i].ld.v.target_id);
+			close(fd);
 			return (error);
 		}
 		printf("%6s ",
@@ -440,10 +484,11 @@ show_drives(int ac, char **av)
 		return (error);
 	}
 
+	list = NULL;
 	if (mfi_pd_get_list(fd, &list, NULL) < 0) {
 		error = errno;
 		warn("Failed to get drive list");
-		return (error);
+		goto error;
 	}
 
 	/* Walk the list of drives to determine width of state column. */
@@ -457,7 +502,7 @@ show_drives(int ac, char **av)
 			error = errno;
 			warn("Failed to fetch info for drive %u",
 			    list->addr[i].device_id);
-			return (error);
+			goto error;
 		}
 		len = strlen(mfi_pdstate(info.fw_state));
 		if (len > state_len)
@@ -478,15 +523,22 @@ show_drives(int ac, char **av)
 			error = errno;
 			warn("Failed to fetch info for drive %u",
 			    list->addr[i].device_id);
-			return (error);
+			goto error;
 		}
 
-		print_pd(&info, state_len, 1);
+		printf("%s ", mfi_drive_name(&info, list->addr[i].device_id,
+		    MFI_DNAME_DEVICE_ID));
+		print_pd(&info, state_len);
+		printf(" %s", mfi_drive_name(&info, list->addr[i].device_id,
+		    MFI_DNAME_ES));
 		printf("\n");
 	}
+	error = 0;
+error:
+	free(list);
 	close(fd);
 
-	return (0);
+	return (error);
 }
 MFI_COMMAND(show, drives, show_drives);
 
@@ -529,7 +581,7 @@ show_firmware(int ac, char **av)
 	u_int i;
 
 	if (ac != 1) {
-		warnx("show drives: extra arguments");
+		warnx("show firmware: extra arguments");
 		return (EINVAL);
 	}
 
@@ -543,6 +595,7 @@ show_firmware(int ac, char **av)
 	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
 		error = errno;
 		warn("Failed to get controller info");
+		close(fd);
 		return (error);
 	}
 
@@ -574,3 +627,121 @@ show_firmware(int ac, char **av)
 	return (0);
 }
 MFI_COMMAND(show, firmware, show_firmware);
+
+static int
+show_progress(int ac, char **av)
+{
+	struct mfi_ld_list llist;
+	struct mfi_pd_list *plist;
+	struct mfi_ld_info linfo;
+	struct mfi_pd_info pinfo;
+	int busy, error, fd;
+	u_int i;
+	uint16_t device_id;
+	uint8_t target_id;
+
+	if (ac != 1) {
+		warnx("show progress: extra arguments");
+		return (EINVAL);
+	}
+
+	fd = mfi_open(mfi_unit);
+	if (fd < 0) {
+		error = errno;
+		warn("mfi_open");
+		return (error);
+	}
+
+	if (mfi_ld_get_list(fd, &llist, NULL) < 0) {
+		error = errno;
+		warn("Failed to get volume list");
+		close(fd);
+		return (error);
+	}
+	if (mfi_pd_get_list(fd, &plist, NULL) < 0) {
+		error = errno;
+		warn("Failed to get drive list");
+		close(fd);
+		return (error);
+	}
+
+	busy = 0;
+	for (i = 0; i < llist.ld_count; i++) {
+		target_id = llist.ld_list[i].ld.v.target_id;
+		if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) {
+			error = errno;
+			warn("Failed to get info for volume %s",
+			    mfi_volume_name(fd, target_id));
+			free(plist);
+			close(fd);
+			return (error);
+		}
+		if (linfo.progress.active & MFI_LD_PROGRESS_CC) {
+			printf("volume %s ", mfi_volume_name(fd, target_id));
+			mfi_display_progress("Consistency Check",
+			    &linfo.progress.cc);
+			busy = 1;
+		}
+		if (linfo.progress.active & MFI_LD_PROGRESS_BGI) {
+			printf("volume %s ", mfi_volume_name(fd, target_id));
+			mfi_display_progress("Background Init",
+			    &linfo.progress.bgi);
+			busy = 1;
+		}
+		if (linfo.progress.active & MFI_LD_PROGRESS_FGI) {
+			printf("volume %s ", mfi_volume_name(fd, target_id));
+			mfi_display_progress("Foreground Init",
+			    &linfo.progress.fgi);
+			busy = 1;
+		}
+		if (linfo.progress.active & MFI_LD_PROGRESS_RECON) {
+			printf("volume %s ", mfi_volume_name(fd, target_id));
+			mfi_display_progress("Reconstruction",
+			    &linfo.progress.recon);
+			busy = 1;
+		}
+	}
+
+	for (i = 0; i < plist->count; i++) {
+		if (plist->addr[i].scsi_dev_type != 0)
+			continue;
+
+		device_id = plist->addr[i].device_id;
+		if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) {
+			error = errno;
+			warn("Failed to fetch info for drive %u", device_id);
+			free(plist);
+			close(fd);
+			return (error);
+		}
+
+		if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) {
+			printf("drive %s ", mfi_drive_name(NULL, device_id,
+			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
+			mfi_display_progress("Rebuild", &pinfo.prog_info.rbld);
+			busy = 1;
+		}
+		if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) {
+			printf("drive %s ", mfi_drive_name(NULL, device_id,
+			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
+			mfi_display_progress("Patrol Read",
+			    &pinfo.prog_info.patrol);
+			busy = 1;
+		}
+		if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) {
+			printf("drive %s ", mfi_drive_name(NULL, device_id,
+			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
+			mfi_display_progress("Clear", &pinfo.prog_info.clear);
+			busy = 1;
+		}
+	}
+
+	free(plist);
+	close(fd);
+
+	if (!busy)
+		printf("No activity in progress for adapter mfi%d\n", mfi_unit);
+
+	return (0);
+}
+MFI_COMMAND(show, progress, show_progress);
diff --git a/usr.sbin/mfiutil/mfi_volume.c b/usr.sbin/mfiutil/mfi_volume.c
index 3f3c0d3..b9ea2cc 100644
--- a/usr.sbin/mfiutil/mfi_volume.c
+++ b/usr.sbin/mfiutil/mfi_volume.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfi_volume.c,v 1.2 2010/10/26 19:11:09 jhb Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfi_volume.c,v 1.4 2011/06/09 19:52:28 bz Exp $
  */
 
 #include <sys/types.h>
@@ -138,6 +138,10 @@ update_cache_policy(int fd, struct mfi_ld_props *props, uint8_t new_policy,
 		    policy & MR_LD_CACHE_READ_AHEAD ?
 		    (policy & MR_LD_CACHE_READ_ADAPTIVE ?
 		    "adaptive" : "always") : "none");
+	if (changes & MR_LD_CACHE_WRITE_CACHE_BAD_BBU)
+		printf("%s write caching with bad BBU\n",
+		    policy & MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "Enabling" :
+		    "Disabling");
 
 	props->default_cache_policy = policy;
 	if (mfi_ld_set_props(fd, props) < 0) {
@@ -170,19 +174,21 @@ volume_cache(int ac, char **av)
 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
 		error = errno;
 		warn("Invalid volume: %s", av[1]);
+		close(fd);
 		return (error);
 	}
 
 	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
 		error = errno;
 		warn("Failed to fetch volume properties");
+		close(fd);
 		return (error);
 	}
 
 	if (ac == 2) {
 		printf("mfi%u volume %s cache settings:\n", mfi_unit,
 		    mfi_volume_name(fd, target_id));
-		printf("      I/O caching: ");
+		printf("             I/O caching: ");
 		switch (props.default_cache_policy &
 		    (MR_LD_CACHE_ALLOW_WRITE_CACHE |
 		    MR_LD_CACHE_ALLOW_READ_CACHE)) {
@@ -200,14 +206,17 @@ volume_cache(int ac, char **av)
 			printf("writes and reads\n");
 			break;
 		}
-		printf("    write caching: %s\n",
+		printf("           write caching: %s\n",
 		    props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ?
 		    "write-back" : "write-through");
-		printf("       read ahead: %s\n",
+		printf("write cache with bad BBU: %s\n",
+		    props.default_cache_policy &
+		    MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "enabled" : "disabled");
+		printf("              read ahead: %s\n",
 		    props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ?
 		    (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ?
 		    "adaptive" : "always") : "none");
-		printf("drive write cache: ");
+		printf("       drive write cache: ");
 		switch (props.disk_cache_policy) {
 		case MR_PD_CACHE_UNCHANGED:
 			printf("default\n");
@@ -257,6 +266,7 @@ volume_cache(int ac, char **av)
 		else if (strcmp(av[2], "read-ahead") == 0) {
 			if (ac < 4) {
 				warnx("cache: read-ahead setting required");
+				close(fd);
 				return (EINVAL);
 			}
 			if (strcmp(av[3], "none") == 0)
@@ -268,14 +278,33 @@ volume_cache(int ac, char **av)
 				    MR_LD_CACHE_READ_ADAPTIVE;
 			else {
 				warnx("cache: invalid read-ahead setting");
+				close(fd);
 				return (EINVAL);
 			}
 			error = update_cache_policy(fd, &props, policy,
 			    MR_LD_CACHE_READ_AHEAD |
 			    MR_LD_CACHE_READ_ADAPTIVE);
+		} else if (strcmp(av[2], "bad-bbu-write-cache") == 0) {
+			if (ac < 4) {
+				warnx("cache: bad BBU setting required");
+				close(fd);
+				return (EINVAL);
+			}
+			if (strcmp(av[3], "enable") == 0)
+				policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU;
+			else if (strcmp(av[3], "disable") == 0)
+				policy = 0;
+			else {
+				warnx("cache: invalid bad BBU setting");
+				close(fd);
+				return (EINVAL);
+			}
+			error = update_cache_policy(fd, &props, policy,
+			    MR_LD_CACHE_WRITE_CACHE_BAD_BBU);
 		} else if (strcmp(av[2], "write-cache") == 0) {
 			if (ac < 4) {
 				warnx("cache: write-cache setting required");
+				close(fd);
 				return (EINVAL);
 			}
 			if (strcmp(av[3], "enable") == 0)
@@ -286,6 +315,7 @@ volume_cache(int ac, char **av)
 				policy = MR_PD_CACHE_UNCHANGED;
 			else {
 				warnx("cache: invalid write-cache setting");
+				close(fd);
 				return (EINVAL);
 			}
 			error = 0;
@@ -309,6 +339,7 @@ volume_cache(int ac, char **av)
 			}
 		} else {
 			warnx("cache: Invalid command");
+			close(fd);
 			return (EINVAL);
 		}
 	}
@@ -345,12 +376,14 @@ volume_name(int ac, char **av)
 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
 		error = errno;
 		warn("Invalid volume: %s", av[1]);
+		close(fd);
 		return (error);
 	}
 
 	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
 		error = errno;
 		warn("Failed to fetch volume properties");
+		close(fd);
 		return (error);
 	}
 
@@ -361,6 +394,7 @@ volume_name(int ac, char **av)
 	if (mfi_ld_set_props(fd, &props) < 0) {
 		error = errno;
 		warn("Failed to set volume properties");
+		close(fd);
 		return (error);
 	}
 
@@ -393,6 +427,7 @@ volume_progress(int ac, char **av)
 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
 		error = errno;
 		warn("Invalid volume: %s", av[1]);
+		close(fd);
 		return (error);
 	}
 
@@ -401,6 +436,7 @@ volume_progress(int ac, char **av)
 		error = errno;
 		warn("Failed to fetch info for volume %s",
 		    mfi_volume_name(fd, target_id));
+		close(fd);
 		return (error);
 	}
 
diff --git a/usr.sbin/mfiutil/mfiutil.8 b/usr.sbin/mfiutil/mfiutil.8
index a87ce27..75134c9 100644
--- a/usr.sbin/mfiutil/mfiutil.8
+++ b/usr.sbin/mfiutil/mfiutil.8
@@ -25,9 +25,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/usr.sbin/mfiutil/mfiutil.8,v 1.5 2010/08/06 14:33:42 joel Exp $
+.\" $FreeBSD: src/usr.sbin/mfiutil/mfiutil.8,v 1.8 2011/06/20 21:28:50 bz Exp $
 .\"
-.Dd November 30, 2010
+.Dd August 1, 2011
 .Dt MFIUTIL 8
 .Os
 .Sh NAME
@@ -43,6 +43,8 @@
 .Op Fl u Ar unit
 .Cm show battery
 .Nm
+.Op Fl d
+.Op Fl e
 .Op Fl u Ar unit
 .Cm show config
 .Nm
@@ -63,9 +65,16 @@
 .Op Fl u Ar unit
 .Cm show logstate
 .Nm
+.Op Fl d
+.Op Fl e
 .Op Fl u Ar unit
 .Cm show patrol
 .Nm
+.Op Fl d
+.Op Fl e
+.Op Fl u Ar unit
+.Cm show progress
+.Nm
 .Op Fl u Ar unit
 .Cm show volumes
 .Nm
@@ -152,15 +161,19 @@ If no unit is specified,
 then unit 0 is used.
 .El
 .Pp
-Volumes may be specified in two forms.
-First,
-a volume may be identified by its target ID.
-Second,
-on the volume may be specified by the corresponding
-.Em mfidX
-device,
-such as
-.Em mfid0 .
+Various commands accept either or both of the two options:
+.Bl -tag -width indent
+.It Fl d
+Print numeric device IDs as drive identifier.
+This is the default.
+Useful in combination with
+.Fl e
+to print both, numeric device IDs and enclosure:slot information.
+.It Fl e
+Print drive identifiers in enclosure:slot form.
+See next paragraph on format details in context of input rather than
+output.
+.El
 .Pp
 Drives may be specified in two forms.
 First,
@@ -181,6 +194,16 @@ and
 is the slot for each drive as displayed in
 .Cm show drives .
 .Pp
+Volumes may be specified in two forms.
+First,
+a volume may be identified by its target ID.
+Second,
+on the volume may be specified by the corresponding
+.Em mfidX
+device,
+such as
+.Em mfid0 .
+.Pp
 The
 .Nm
 utility supports several different groups of commands.
@@ -296,6 +319,9 @@ Lists all of the firmware images present on the controller.
 Display the various sequence numbers associated with the event log.
 .It Cm show patrol
 Display the status of the controller's patrol read operation.
+.It Cm show progress
+Report the current progress and estimated completion time for active
+operations on all volumes and drives.
 .It Cm show volumes
 Lists all of the logical volumes managed by the controller.
 .El
@@ -367,7 +393,7 @@ Enable caching only for write I/O operations.
 Use write-back policy for cached writes.
 .It Cm write-through
 Use write-through policy for cached writes.
-.It Cm read-ahead Op Ar value
+.It Cm read-ahead Ar value
 Set the read ahead policy for cached reads.
 The
 .Ar value
@@ -376,7 +402,18 @@ argument can be set to either
 .Dq adaptive ,
 or
 .Dq always .
-.It Cm write-cache Op Ar value
+.It Cm bad-bbu-write-cache Ar value
+Control the behavior of I/O write caching if the battery is dead or
+missing.
+The
+.Ar value
+argument can be set to either
+.Dq disable
+or
+.Dq enable .
+In general this setting should be left disabled to avoid data loss when
+the system loses power.
+.It Cm write-cache Ar value
 Control the write caches on the physical drives backing
 .Ar volume .
 The
diff --git a/usr.sbin/mfiutil/mfiutil.c b/usr.sbin/mfiutil/mfiutil.c
index f73cf97..df45238 100644
--- a/usr.sbin/mfiutil/mfiutil.c
+++ b/usr.sbin/mfiutil/mfiutil.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfiutil.c,v 1.2 2010/10/10 20:37:38 randi Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfiutil.c,v 1.5 2011/06/20 21:28:50 bz Exp $
  */
 
 #include <sys/errno.h>
@@ -45,11 +45,13 @@ MFI_TABLE(top, abort);
 
 int mfi_unit;
 
+u_int mfi_opts;
+
 static void
 usage(void)
 {
 
-	fprintf(stderr, "usage: mfiutil [-u unit] <command> ...\n\n");
+	fprintf(stderr, "usage: mfiutil [-de] [-u unit] <command> ...\n\n");
 	fprintf(stderr, "Commands include:\n");
 	fprintf(stderr, "    version\n");
 	fprintf(stderr, "    show adapter              - display controller information\n");
@@ -58,8 +60,10 @@ usage(void)
 	fprintf(stderr, "    show drives               - list physical drives\n");
 	fprintf(stderr, "    show events               - display event log\n");
 	fprintf(stderr, "    show firmware             - list firmware images\n");
+	fprintf(stderr, "    show logstate             - display event log sequence numbers\n");
 	fprintf(stderr, "    show volumes              - list logical volumes\n");
 	fprintf(stderr, "    show patrol               - display patrol read status\n");
+	fprintf(stderr, "    show progress             - display status of active operations\n");
 	fprintf(stderr, "    fail <drive>              - fail a physical drive\n");
 	fprintf(stderr, "    good <drive>              - mark a bad physical drive as good\n");
 	fprintf(stderr, "    rebuild <drive>           - mark failed drive ready for rebuild\n");
@@ -106,8 +110,14 @@ main(int ac, char **av)
 	struct mfiutil_command **cmd;
 	int ch;
 
-	while ((ch = getopt(ac, av, "u:")) != -1) {
+	while ((ch = getopt(ac, av, "deu:")) != -1) {
 		switch (ch) {
+		case 'd':
+			mfi_opts |= MFI_DNAME_DEVICE_ID;
+			break;
+		case 'e':
+			mfi_opts |= MFI_DNAME_ES;
+			break;
 		case 'u':
 			mfi_unit = atoi(optarg);
 			break;
diff --git a/usr.sbin/mfiutil/mfiutil.h b/usr.sbin/mfiutil/mfiutil.h
index 9a2d3db..69f5bd3 100644
--- a/usr.sbin/mfiutil/mfiutil.h
+++ b/usr.sbin/mfiutil/mfiutil.h
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/mfiutil/mfiutil.h,v 1.1 2009/08/13 23:18:45 scottl Exp $
+ * $FreeBSD: src/usr.sbin/mfiutil/mfiutil.h,v 1.2 2011/06/20 21:28:50 bz Exp $
  */
 
 #ifndef __MFIUTIL_H__
@@ -117,7 +117,13 @@ struct mfiutil_command {
 	}								\
 	MFI_COMMAND(set, name, mfiutil_ ## name ## _table_handler)
 
+/* Drive name printing options */
+#define	MFI_DNAME_ES		0x0001	/* E%u:S%u */
+#define	MFI_DNAME_DEVICE_ID	0x0002	/* %u */
+#define	MFI_DNAME_HONOR_OPTS	0x8000	/* Allow cmd line to override default */
+
 extern int mfi_unit;
+extern u_int mfi_opts;
 
 void	mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref);
 void	mbox_store_pdref(uint8_t *mbox, union mfi_pd_ref *ref);
@@ -145,5 +151,7 @@ int	mfi_pd_get_info(int fd, uint16_t device_id, struct mfi_pd_info *info,
 int	mfi_pd_get_list(int fd, struct mfi_pd_list **listp, uint8_t *statusp);
 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);
 
 #endif /* !__MFIUTIL_H__ */
-- 
1.7.4.4

