Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic After discussion on tech-kern@, fix performance i...



details:   https://anonhg.NetBSD.org/src/rev/9ae7ccb56b4e
branches:  trunk
changeset: 781207:9ae7ccb56b4e
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Sun Aug 26 16:05:29 2012 +0000

description:
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

diffstat:

 sys/dev/ic/mfi.c    |  278 +++++++++++++++++++++++++++++++++++++++++++++------
 sys/dev/ic/mfireg.h |   87 ++++++++++++++++-
 sys/dev/ic/mfivar.h |    4 +-
 3 files changed, 332 insertions(+), 37 deletions(-)

diffs (truncated from 675 to 300 lines):

diff -r 4918b312029b -r 9ae7ccb56b4e sys/dev/ic/mfi.c
--- a/sys/dev/ic/mfi.c  Sun Aug 26 15:41:01 2012 +0000
+++ b/sys/dev/ic/mfi.c  Sun Aug 26 16:05:29 2012 +0000
@@ -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 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 @@
                                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 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 @@
        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 @@
        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 @@
        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 @@
 #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 @@
        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 @@
                        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 @@
        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 @@
                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 @@
                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 @@
 
 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;



Home | Main Index | Thread Index | Old Index