Module Name:    src
Committed By:   bouyer
Date:           Sun Aug 26 16:05:29 UTC 2012

Modified Files:
        src/sys/dev/ic: mfi.c mfireg.h mfivar.h

Log Message:
After discussion on tech-kern@, fix performance issue related to
cache flush commands from WAPBL, by skipping the cache flush if the
BBU is present and considered good. Users which still want the write back
cache with a non-working BBU can set vfs.wapbl.flush_disk_cache to 0.
- add commands to monitor the BBU state. Add a boolean BBU sensor
  to monitor the BBU state via sysmon_envsys(9).
- if the BBU is considered good, turn SCSI_SYNCHRONIZE_CACHE_10 and
  SCSI_SYNCHRONIZE_CACHE_16 commands from upper layer into NOOPs.
  While there, handle SCSI_SYNCHRONIZE_CACHE_16 in addition to
  SCSI_SYNCHRONIZE_CACHE_10.
- Add a shutdown pmf(9) handler, which flushes the cache and shutdown the
  firmware
- on detach, also flush cache and shutdown firmware.
- on attach, print the firmware-provided name, and the BBU state
Tested on a LSI MegaRAID SAS 9265-8i and a PERC 5/i Integrated


To generate a diff of this commit:
cvs rdiff -u -r1.44 -r1.45 src/sys/dev/ic/mfi.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/ic/mfireg.h
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/ic/mfivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/mfi.c
diff -u src/sys/dev/ic/mfi.c:1.44 src/sys/dev/ic/mfi.c:1.45
--- src/sys/dev/ic/mfi.c:1.44	Thu Aug 23 12:24:33 2012
+++ src/sys/dev/ic/mfi.c	Sun Aug 26 16:05:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: mfi.c,v 1.44 2012/08/23 12:24:33 bouyer Exp $ */
+/* $NetBSD: mfi.c,v 1.45 2012/08/26 16:05:29 bouyer Exp $ */
 /* $OpenBSD: mfi.c,v 1.66 2006/11/28 23:59:45 dlg Exp $ */
 
 /*
@@ -73,7 +73,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.44 2012/08/23 12:24:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.45 2012/08/26 16:05:29 bouyer Exp $");
 
 #include "bio.h"
 
@@ -133,6 +133,12 @@ static void		mfi_freemem(struct mfi_soft
 static int		mfi_transition_firmware(struct mfi_softc *);
 static int		mfi_initialize_firmware(struct mfi_softc *);
 static int		mfi_get_info(struct mfi_softc *);
+static int		mfi_get_bbu(struct mfi_softc *,
+			    struct mfi_bbu_status *);
+/* return codes for mfi_get_bbu */
+#define MFI_BBU_GOOD	0
+#define MFI_BBU_BAD	1
+#define MFI_BBU_UNKNOWN	2
 static uint32_t		mfi_read(struct mfi_softc *, bus_size_t);
 static void		mfi_write(struct mfi_softc *, bus_size_t, uint32_t);
 static int		mfi_poll(struct mfi_ccb *);
@@ -144,8 +150,8 @@ static int		mfi_scsi_ld_io(struct mfi_cc
 				uint64_t, uint32_t);
 static void		mfi_scsi_ld_done(struct mfi_ccb *);
 static void		mfi_scsi_xs_done(struct mfi_ccb *, int, int);
-static int		mfi_mgmt_internal(struct mfi_softc *,
-			    uint32_t, uint32_t, uint32_t, void *, uint8_t *);
+static int		mfi_mgmt_internal(struct mfi_softc *, uint32_t,
+			    uint32_t, uint32_t, void *, uint8_t *, bool);
 static int		mfi_mgmt(struct mfi_ccb *,struct scsipi_xfer *,
 			    uint32_t, uint32_t, uint32_t, void *, uint8_t *);
 static void		mfi_mgmt_done(struct mfi_ccb *);
@@ -167,6 +173,9 @@ static int		mfi_destroy_sensors(struct m
 static void		mfi_sensor_refresh(struct sysmon_envsys *,
 				envsys_data_t *);
 #endif /* NBIO > 0 */
+static bool		mfi_shutdown(device_t, int);
+static bool		mfi_suspend(device_t, const pmf_qual_t *);
+static bool		mfi_resume(device_t, const pmf_qual_t *);
 
 static uint32_t 	mfi_xscale_fw_state(struct mfi_softc *sc);
 static void 		mfi_xscale_intr_ena(struct mfi_softc *sc);
@@ -274,7 +283,7 @@ mfi_get_ccb(struct mfi_softc *sc)
 	splx(s);
 
 	DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb);
-	if (ccb == NULL)
+	if (__predict_false(ccb == NULL && sc->sc_running))
 		aprint_error_dev(sc->sc_dev, "out of ccb\n");
 
 	return ccb;
@@ -646,7 +655,7 @@ mfi_get_info(struct mfi_softc *sc)
 	DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc));
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN,
-	    sizeof(sc->sc_info), &sc->sc_info, NULL))
+	    sizeof(sc->sc_info), &sc->sc_info, NULL, cold ? true : false))
 		return 1;
 
 #ifdef MFI_DEBUG
@@ -796,6 +805,63 @@ mfi_get_info(struct mfi_softc *sc)
 	return 0;
 }
 
+static int
+mfi_get_bbu(struct mfi_softc *sc, struct mfi_bbu_status *stat)
+{
+	DNPRINTF(MFI_D_MISC, "%s: mfi_get_bbu\n", DEVNAME(sc));
+
+	if (mfi_mgmt_internal(sc, MR_DCMD_BBU_GET_STATUS, MFI_DATA_IN,
+	    sizeof(*stat), stat, NULL, cold ? true : false))
+		return MFI_BBU_UNKNOWN;
+#ifdef MFI_DEBUG
+	printf("bbu type %d, voltage %d, current %d, temperature %d, "
+	    "status 0x%x\n", stat->battery_type, stat->voltage, stat->current,
+	    stat->temperature, stat->fw_status);
+	printf("details: ");
+	switch(stat->battery_type) {
+	case MFI_BBU_TYPE_IBBU:
+		printf("guage %d relative charge %d charger state %d "
+		    "charger ctrl %d\n", stat->detail.ibbu.gas_guage_status,
+		    stat->detail.ibbu.relative_charge ,
+		    stat->detail.ibbu.charger_system_state ,
+		    stat->detail.ibbu.charger_system_ctrl);
+		printf("\tcurrent %d abs charge %d max error %d\n",
+		    stat->detail.ibbu.charging_current ,
+		    stat->detail.ibbu.absolute_charge ,
+		    stat->detail.ibbu.max_error);
+		break;
+	case MFI_BBU_TYPE_BBU:
+		printf("guage %d relative charge %d charger state %d\n",
+		    stat->detail.ibbu.gas_guage_status,
+		    stat->detail.bbu.relative_charge ,
+		    stat->detail.bbu.charger_status );
+		printf("\trem capacity %d fyll capacity %d SOH %d\n",
+		    stat->detail.bbu.remaining_capacity ,
+		    stat->detail.bbu.full_charge_capacity ,
+		    stat->detail.bbu.is_SOH_good);
+	default:
+		printf("\n");
+	}
+#endif
+	switch(stat->battery_type) {
+	case MFI_BBU_TYPE_BBU:
+		return (stat->detail.bbu.is_SOH_good ? 
+		    MFI_BBU_GOOD : MFI_BBU_BAD);
+	case MFI_BBU_TYPE_NONE:
+		return MFI_BBU_UNKNOWN;
+	default:
+		if (stat->fw_status &
+		    (MFI_BBU_STATE_PACK_MISSING |
+		     MFI_BBU_STATE_VOLTAGE_LOW |
+		     MFI_BBU_STATE_TEMPERATURE_HIGH |
+		     MFI_BBU_STATE_LEARN_CYC_FAIL |
+		     MFI_BBU_STATE_LEARN_CYC_TIMEOUT |
+		     MFI_BBU_STATE_I2C_ERR_DETECT))
+			return MFI_BBU_BAD;
+		return MFI_BBU_GOOD;
+	}
+}
+
 static void
 mfiminphys(struct buf *bp)
 {
@@ -849,8 +915,7 @@ mfi_detach(struct mfi_softc *sc, int fla
 #endif /* NBIO > 0 */
 
 	mfi_intr_disable(sc);
-
-	/* TBD: shutdown firmware */
+	mfi_shutdown(sc->sc_dev, 0);
 
 	if (sc->sc_ioptype == MFI_IOP_TBOLT) {
 		workqueue_destroy(sc->sc_ldsync_wq);
@@ -872,6 +937,51 @@ mfi_detach(struct mfi_softc *sc, int fla
 	return 0;
 }
 
+static bool
+mfi_shutdown(device_t dev, int how)
+{
+	struct mfi_softc	*sc = device_private(dev);
+	uint8_t			mbox[MFI_MBOX_SIZE];
+	int s = splbio();
+	DNPRINTF(MFI_D_MISC, "%s: mfi_shutdown\n", DEVNAME(sc));
+	if (sc->sc_running) {
+		mbox[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
+		if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_CACHE_FLUSH,
+		    MFI_DATA_NONE, 0, NULL, mbox, true)) {
+			aprint_error_dev(dev, "shutdown: cache flush failed\n");
+			goto fail;
+		}
+
+		mbox[0] = 0;
+		if (mfi_mgmt_internal(sc, MR_DCMD_CTRL_SHUTDOWN,
+		    MFI_DATA_NONE, 0, NULL, mbox, true)) {
+			aprint_error_dev(dev, "shutdown: "
+			    "firmware shutdown failed\n");
+			goto fail;
+		}
+		sc->sc_running = false;
+	}
+	splx(s);
+	return true;
+fail:
+	splx(s);
+	return false;
+}
+
+static bool
+mfi_suspend(device_t dev, const pmf_qual_t *q)
+{
+	/* XXX to be implemented */
+	return false;
+}
+
+static bool
+mfi_resume(device_t dev, const pmf_qual_t *q)
+{
+	/* XXX to be implemented */
+	return false;
+}
+
 int
 mfi_attach(struct mfi_softc *sc, enum mfi_iop iop)
 {
@@ -1032,18 +1142,55 @@ mfi_attach(struct mfi_softc *sc, enum mf
 			goto noinit;
 		}
 	}
+	sc->sc_running = true;
 
 	if (mfi_get_info(sc)) {
 		aprint_error_dev(sc->sc_dev,
 		    "could not retrieve controller information\n");
 		goto noinit;
 	}
-
 	aprint_normal_dev(sc->sc_dev,
-	    "logical drives %d, version %s, %dMB RAM\n",
+	    "%s version %s\n",
+	    sc->sc_info.mci_product_name,
+	    sc->sc_info.mci_package_version);
+
+
+	aprint_normal_dev(sc->sc_dev, "logical drives %d, %dMB RAM, ",
 	    sc->sc_info.mci_lds_present,
-	    sc->sc_info.mci_package_version,
 	    sc->sc_info.mci_memory_size);
+	sc->sc_bbuok = false;
+	if (sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU) {
+		struct mfi_bbu_status	bbu_stat;
+		int mfi_bbu_status = mfi_get_bbu(sc, &bbu_stat);
+		aprint_normal("BBU type ");
+		switch (bbu_stat.battery_type) {
+		case MFI_BBU_TYPE_BBU:
+			aprint_normal("BBU");
+			break;
+		case MFI_BBU_TYPE_IBBU:
+			aprint_normal("IBBU");
+			break;
+		default:
+			aprint_normal("unknown type %d", bbu_stat.battery_type);
+		}
+		aprint_normal(", status ");
+		switch(mfi_bbu_status) {
+		case MFI_BBU_GOOD:
+			aprint_normal("good\n");
+			sc->sc_bbuok = true;
+			break;
+		case MFI_BBU_BAD:
+			aprint_normal("bad\n");
+			break;
+		case MFI_BBU_UNKNOWN:
+			aprint_normal("unknown\n");
+			break;
+		default:
+			panic("mfi_bbu_status");
+		}
+	} else {
+		aprint_normal("BBU not present\n");
+	}
 
 	sc->sc_ld_cnt = sc->sc_info.mci_lds_present;
 	sc->sc_max_ld = sc->sc_ld_cnt;
@@ -1082,6 +1229,11 @@ mfi_attach(struct mfi_softc *sc, enum mf
 	if (mfi_create_sensors(sc) != 0)
 		aprint_error_dev(sc->sc_dev, "unable to create sensors\n");
 #endif /* NBIO > 0 */
+	if (!pmf_device_register1(sc->sc_dev, mfi_suspend, mfi_resume,
+	    mfi_shutdown)) {
+		aprint_error_dev(sc->sc_dev,
+		    "couldn't establish power handler\n");
+	}
 
 	return 0;
 noinit:
@@ -1439,6 +1591,16 @@ mfi_scsipi_request(struct scsipi_channel
 		splx(s);
 		return;
 	}
+	if ((xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_10 ||
+	    xs->cmd->opcode == SCSI_SYNCHRONIZE_CACHE_16) && sc->sc_bbuok) {
+		/* the cache is stable storage, don't flush */
+		xs->error = XS_NOERROR;
+		xs->status = SCSI_OK;
+		xs->resid = 0;
+		scsipi_done(xs);
+		splx(s);
+		return;
+	}
 
 	if ((ccb = mfi_get_ccb(sc)) == NULL) {
 		DNPRINTF(MFI_D_CMD, "%s: mfi_scsipi_request no ccb\n", DEVNAME(sc));
@@ -1491,6 +1653,7 @@ mfi_scsipi_request(struct scsipi_channel
 		break;
 
 	case SCSI_SYNCHRONIZE_CACHE_10:
+	case SCSI_SYNCHRONIZE_CACHE_16:
 		mbox[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
 		if (mfi_mgmt(ccb, xs,
 		    MR_DCMD_CTRL_CACHE_FLUSH, MFI_DATA_NONE, 0, NULL, mbox)) {
@@ -1644,7 +1807,7 @@ mfi_create_sgl(struct mfi_ccb *ccb, int 
 
 static int
 mfi_mgmt_internal(struct mfi_softc *sc, uint32_t opc, uint32_t dir,
-    uint32_t len, void *buf, uint8_t *mbox)
+    uint32_t len, void *buf, uint8_t *mbox, bool poll)
 {
 	struct mfi_ccb		*ccb;
 	int			rv = 1;
@@ -1655,7 +1818,7 @@ mfi_mgmt_internal(struct mfi_softc *sc, 
 	if (rv)
 		return rv;
 
-	if (cold) {
+	if (poll) {
 		rv = 1;
 		if (mfi_poll(ccb))
 			goto done;
@@ -1825,7 +1988,7 @@ mfi_ioctl_inq(struct mfi_softc *sc, stru
 	/* get figures */
 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
 	if (mfi_mgmt_internal(sc, MD_DCMD_CONF_GET, MFI_DATA_IN,
-	    sizeof *cfg, cfg, NULL))
+	    sizeof *cfg, cfg, NULL, false))
 		goto freeme;
 
 	strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
@@ -1848,7 +2011,7 @@ mfi_ioctl_vol(struct mfi_softc *sc, stru
 	    DEVNAME(sc), bv->bv_volid);
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
-	    sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL))
+	    sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL, false))
 		goto done;
 
 	i = bv->bv_volid;
@@ -1857,7 +2020,7 @@ mfi_ioctl_vol(struct mfi_softc *sc, stru
 	    DEVNAME(sc), mbox[0]);
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN,
-	    sizeof(sc->sc_ld_details), &sc->sc_ld_details, mbox))
+	    sizeof(sc->sc_ld_details), &sc->sc_ld_details, mbox, false))
 		goto done;
 
 	if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
@@ -1949,7 +2112,7 @@ mfi_ioctl_disk(struct mfi_softc *sc, str
 	/* send single element command to retrieve size for full structure */
 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
 	if (mfi_mgmt_internal(sc, MD_DCMD_CONF_GET, MFI_DATA_IN,
-	    sizeof *cfg, cfg, NULL))
+	    sizeof *cfg, cfg, NULL, false))
 		goto freeme;
 
 	size = cfg->mfc_size;
@@ -1958,7 +2121,7 @@ mfi_ioctl_disk(struct mfi_softc *sc, str
 	/* memory for read config */
 	cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
 	if (mfi_mgmt_internal(sc, MD_DCMD_CONF_GET, MFI_DATA_IN,
-	    size, cfg, NULL))
+	    size, cfg, NULL, false))
 		goto freeme;
 
 	ar = cfg->mfc_array;
@@ -2023,7 +2186,7 @@ mfi_ioctl_disk(struct mfi_softc *sc, str
 	*((uint16_t *)&mbox) = ar[arr].pd[disk].mar_pd.mfp_id;
 	memset(pd, 0, sizeof(*pd));
 	if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
-	    sizeof *pd, pd, mbox))
+	    sizeof *pd, pd, mbox, false))
 		goto freeme;
 
 	bd->bd_size = pd->mpd_size * 512; /* bytes per block */
@@ -2082,7 +2245,7 @@ mfi_ioctl_alarm(struct mfi_softc *sc, st
 		return EINVAL;
 	}
 
-	if (mfi_mgmt_internal(sc, opc, dir, sizeof(ret), &ret, NULL))
+	if (mfi_mgmt_internal(sc, opc, dir, sizeof(ret), &ret, NULL, false))
 		rv = EINVAL;
 	else
 		if (ba->ba_opcode == BIOC_GASTATUS)
@@ -2111,7 +2274,7 @@ mfi_ioctl_blink(struct mfi_softc *sc, st
 	pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
-	    MFI_PD_LIST_SIZE, pd, NULL))
+	    MFI_PD_LIST_SIZE, pd, NULL, false))
 		goto done;
 
 	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
@@ -2145,7 +2308,7 @@ mfi_ioctl_blink(struct mfi_softc *sc, st
 	}
 
 
-	if (mfi_mgmt_internal(sc, cmd, MFI_DATA_NONE, 0, NULL, mbox))
+	if (mfi_mgmt_internal(sc, cmd, MFI_DATA_NONE, 0, NULL, mbox, false))
 		goto done;
 
 	rv = 0;
@@ -2168,7 +2331,7 @@ mfi_ioctl_setstate(struct mfi_softc *sc,
 	pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
-	    MFI_PD_LIST_SIZE, pd, NULL))
+	    MFI_PD_LIST_SIZE, pd, NULL, false))
 		goto done;
 
 	for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
@@ -2213,7 +2376,7 @@ mfi_ioctl_setstate(struct mfi_softc *sc,
 
 
 	if (mfi_mgmt_internal(sc, MD_DCMD_PD_SET_STATE, MFI_DATA_NONE,
-	    0, NULL, mbox))
+	    0, NULL, mbox, false))
 		goto done;
 
 	rv = 0;
@@ -2246,7 +2409,7 @@ mfi_bio_hs(struct mfi_softc *sc, int vol
 	/* send single element command to retrieve size for full structure */
 	cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
 	if (mfi_mgmt_internal(sc, MD_DCMD_CONF_GET, MFI_DATA_IN,
-	    sizeof *cfg, cfg, NULL))
+	    sizeof *cfg, cfg, NULL, false))
 		goto freeme;
 
 	size = cfg->mfc_size;
@@ -2255,7 +2418,7 @@ mfi_bio_hs(struct mfi_softc *sc, int vol
 	/* memory for read config */
 	cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
 	if (mfi_mgmt_internal(sc, MD_DCMD_CONF_GET, MFI_DATA_IN,
-	    size, cfg, NULL))
+	    size, cfg, NULL, false))
 		goto freeme;
 
 	/* calculate offset to hs structure */
@@ -2281,7 +2444,7 @@ mfi_bio_hs(struct mfi_softc *sc, int vol
 	memset(mbox, 0, sizeof mbox);
 	*((uint16_t *)&mbox) = hs[i].mhs_pd.mfp_id;
 	if (mfi_mgmt_internal(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
-	    sizeof *pd, pd, mbox)) {
+	    sizeof *pd, pd, mbox, false)) {
 		DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n",
 		    DEVNAME(sc));
 		goto freeme;
@@ -2336,7 +2499,7 @@ static int
 mfi_create_sensors(struct mfi_softc *sc)
 {
 	int i;
-	int nsensors = sc->sc_ld_cnt;
+	int nsensors = sc->sc_ld_cnt + 1;
 	int rv;
 
 	sc->sc_sme = sysmon_envsys_create();
@@ -2347,7 +2510,19 @@ mfi_create_sensors(struct mfi_softc *sc)
 		return ENOMEM;
 	}
 
-	for (i = 0; i < nsensors; i++) {
+	/* BBU */
+	sc->sc_sensor[0].units = ENVSYS_INDICATOR;
+	sc->sc_sensor[0].state = ENVSYS_SINVALID;
+	sc->sc_sensor[0].value_cur = 0;
+	/* Enable monitoring for BBU state changes, if present */
+	if (sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU)
+		sc->sc_sensor[0].flags |= ENVSYS_FMONCRITICAL;
+	snprintf(sc->sc_sensor[0].desc,
+	    sizeof(sc->sc_sensor[0].desc), "%s BBU", DEVNAME(sc));
+	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0]))
+		goto out;
+
+	for (i = 1; i < nsensors; i++) {
 		sc->sc_sensor[i].units = ENVSYS_DRIVE;
 		sc->sc_sensor[i].state = ENVSYS_SINVALID;
 		sc->sc_sensor[i].value_cur = ENVSYS_DRIVE_EMPTY;
@@ -2356,7 +2531,7 @@ mfi_create_sensors(struct mfi_softc *sc)
 		/* logical drives */
 		snprintf(sc->sc_sensor[i].desc,
 		    sizeof(sc->sc_sensor[i].desc), "%s:%d",
-		    DEVNAME(sc), i);
+		    DEVNAME(sc), i - 1);
 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
 						&sc->sc_sensor[i]))
 			goto out;
@@ -2388,11 +2563,44 @@ mfi_sensor_refresh(struct sysmon_envsys 
 	int s;
 	int error;
 
-	if (edata->sensor >= sc->sc_ld_cnt)
+	if (edata->sensor >= sc->sc_ld_cnt + 1)
+		return;
+
+	if (edata->sensor == 0) {
+		/* BBU */
+		struct mfi_bbu_status	bbu_stat;
+		int bbu_status;
+		if ((sc->sc_info.mci_hw_present & MFI_INFO_HW_BBU) == 0)
+			return;
+
+		KERNEL_LOCK(1, curlwp);
+		s = splbio();
+		bbu_status = mfi_get_bbu(sc, &bbu_stat);
+		splx(s);
+		KERNEL_UNLOCK_ONE(curlwp);
+		switch(bbu_status) {
+		case MFI_BBU_GOOD:
+			edata->value_cur = 1;
+			edata->state = ENVSYS_SVALID;
+			sc->sc_bbuok = true;
+			break;
+		case MFI_BBU_BAD:
+			edata->value_cur = 0;
+			edata->state = ENVSYS_SCRITICAL;
+			sc->sc_bbuok = false;
+			break;
+		case MFI_BBU_UNKNOWN:
+		default:
+			edata->value_cur = 0;
+			edata->state = ENVSYS_SINVALID;
+			sc->sc_bbuok = false;
+			break;
+		}
 		return;
+	}
 
 	memset(&bv, 0, sizeof(bv));
-	bv.bv_volid = edata->sensor;
+	bv.bv_volid = edata->sensor - 1;
 	KERNEL_LOCK(1, curlwp);
 	s = splbio();
 	error = mfi_ioctl_vol(sc, &bv);
@@ -3180,7 +3388,7 @@ again:
 	}
 
 	if (mfi_mgmt_internal(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
-	    sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL)) {
+	    sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL, false)) {
 		aprint_error_dev(sc->sc_dev, "MR_DCMD_LD_GET_LIST failed\n");
 		goto err;
 	}
@@ -3237,7 +3445,7 @@ static void
 mfi_sync_map_complete(struct mfi_ccb *ccb)
 {
 	struct mfi_softc *sc = ccb->ccb_sc;
-	int aborted = 0;
+	bool aborted = !sc->sc_running;
 
 	DNPRINTF(MFI_D_SYNC, "%s: mfi_sync_map_complete\n",
 	    DEVNAME(ccb->ccb_sc));
@@ -3246,7 +3454,7 @@ mfi_sync_map_complete(struct mfi_ccb *cc
 	free(ccb->ccb_data, M_DEVBUF);
 	if (ccb->ccb_flags & MFI_CCB_F_ERR) {
 		aprint_error_dev(sc->sc_dev, "sync command failed\n");
-		aborted = 1;
+		aborted = true;
 	}
 	mfi_put_ccb(ccb);
 	sc->sc_ldsync_ccb = NULL;

Index: src/sys/dev/ic/mfireg.h
diff -u src/sys/dev/ic/mfireg.h:1.6 src/sys/dev/ic/mfireg.h:1.7
--- src/sys/dev/ic/mfireg.h:1.6	Thu Aug 23 09:59:13 2012
+++ src/sys/dev/ic/mfireg.h	Sun Aug 26 16:05:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: mfireg.h,v 1.6 2012/08/23 09:59:13 bouyer Exp $ */
+/* $NetBSD: mfireg.h,v 1.7 2012/08/26 16:05:29 bouyer Exp $ */
 /* $OpenBSD: mfireg.h,v 1.24 2006/06/19 19:05:45 marco Exp $ */
 /*
  * Copyright (c) 2006 Marco Peereboom <ma...@peereboom.us>
@@ -241,6 +241,9 @@
 #define MR_DCMD_LD_GET_INFO		0x03020000
 #define MR_DCMD_LD_GET_PROPERTIES	0x03030000
 #define MD_DCMD_CONF_GET		0x04010000
+#define MR_DCMD_BBU_GET_STATUS		0x05010000
+#define MR_DCMD_BBU_GET_CAPACITY_INFO	0x05020000
+#define MR_DCMD_BBU_GET_DESIGN_INFO	0x05030000
 #define MR_DCMD_CLUSTER			0x08000000
 #define MR_DCMD_CLUSTER_RESET_ALL	0x08010100
 #define MR_DCMD_CLUSTER_RESET_LD	0x08010200
@@ -1116,6 +1119,88 @@ struct mfi_array {
 	} pd[MFI_MAX_PD_ARRAY];
 } __packed;
 
+/* informations from MR_DCMD_BBU_GET_CAPACITY_INFO */
+struct mfi_bbu_capacity_info {
+	uint16_t		relative_charge;
+	uint16_t		absolute_charge;
+	uint16_t		remaining_capacity;
+	uint16_t		full_charge_capacity;
+	uint16_t		run_time_to_empty;
+	uint16_t		average_time_to_empty;
+	uint16_t		average_time_to_full;
+	uint16_t		cycle_count;
+	uint16_t		max_error;
+	uint16_t		remaining_capacity_alarm;
+	uint16_t		remaining_time_alarm;
+	uint8_t			reserved[26];
+} __packed;
+
+/* informations from MR_DCMD_BBU_GET_DESIGN_INFO */
+struct mfi_bbu_design_info {
+	uint32_t		mfg_date;
+	uint16_t		design_capacity;
+	uint16_t		design_voltage;
+	uint16_t		spec_info;
+	uint16_t		serial_number;
+	uint16_t		pack_stat_config;
+	uint8_t		 	mfg_name[12];
+	uint8_t		 	device_name[8];
+	uint8_t		 	device_chemistry[8];
+	uint8_t		 	mfg_data[8];
+	uint8_t		 	reserved[17];
+} __packed;
+
+struct mfi_ibbu_state {
+	uint16_t		gas_guage_status;
+	uint16_t		relative_charge;
+	uint16_t		charger_system_state;
+	uint16_t		charger_system_ctrl;
+	uint16_t		charging_current;
+	uint16_t		absolute_charge;
+	uint16_t		max_error;
+	uint8_t			reserved[18];
+} __packed;
+
+struct mfi_bbu_state {
+	uint16_t		gas_guage_status;
+	uint16_t		relative_charge;
+	uint16_t		charger_status;
+	uint16_t		remaining_capacity;
+	uint16_t		full_charge_capacity;
+	uint8_t			is_SOH_good;
+	uint8_t			reserved[21];
+} __packed;
+
+union mfi_bbu_status_detail {
+	struct mfi_ibbu_state	ibbu; 
+	struct mfi_bbu_state	bbu;	
+};
+
+/* informations from MR_DCMD_BBU_GET_STATUS */
+struct mfi_bbu_status {
+	uint8_t			battery_type;
+#define MFI_BBU_TYPE_NONE	0	
+#define MFI_BBU_TYPE_IBBU	1	
+#define MFI_BBU_TYPE_BBU	2	
+	uint8_t			reserved;
+	uint16_t		voltage;
+	int16_t			current;
+	uint16_t		temperature;
+	uint32_t		fw_status;
+#define MFI_BBU_STATE_PACK_MISSING	(1 << 0)
+#define MFI_BBU_STATE_VOLTAGE_LOW	(1 << 1)
+#define MFI_BBU_STATE_TEMPERATURE_HIGH	(1 << 2)
+#define MFI_BBU_STATE_CHARGE_ACTIVE	(1 << 3)
+#define MFI_BBU_STATE_DISCHARGE_ACTIVE	(1 << 4)
+#define MFI_BBU_STATE_LEARN_CYC_REQ	(1 << 5)
+#define MFI_BBU_STATE_LEARN_CYC_ACTIVE	(1 << 6)
+#define MFI_BBU_STATE_LEARN_CYC_FAIL	(1 << 7)
+#define MFI_BBU_STATE_LEARN_CYC_TIMEOUT (1 << 8)
+#define MFI_BBU_STATE_I2C_ERR_DETECT	(1 << 9)
+	uint8_t			pad[20];
+	union mfi_bbu_status_detail detail;
+} __packed;
+
 struct mfi_hotspare {
 	struct mfi_pd	mhs_pd;
 	uint8_t		mhs_type;

Index: src/sys/dev/ic/mfivar.h
diff -u src/sys/dev/ic/mfivar.h:1.18 src/sys/dev/ic/mfivar.h:1.19
--- src/sys/dev/ic/mfivar.h:1.18	Thu Aug 23 09:59:13 2012
+++ src/sys/dev/ic/mfivar.h	Sun Aug 26 16:05:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: mfivar.h,v 1.18 2012/08/23 09:59:13 bouyer Exp $ */
+/* $NetBSD: mfivar.h,v 1.19 2012/08/26 16:05:29 bouyer Exp $ */
 /* $OpenBSD: mfivar.h,v 1.28 2006/08/31 18:18:46 marco Exp $ */
 /*
  * Copyright (c) 2006 Marco Peereboom <ma...@peereboom.us>
@@ -206,6 +206,8 @@ struct mfi_softc {
 
 	struct sysmon_envsys    *sc_sme;
 	envsys_data_t		*sc_sensor;
+	bool			sc_bbuok;
+	bool			sc_running;
 
 	device_t		sc_child;
 };

Reply via email to