Current-Users archive

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

ipmi(4) sensor driver update



After the recent update to sysmon_envsys(9) I've started reviewing some of the existing sensor drivers with an eye to providing some enhanced functionality.

The sys/arch/x86/x86/ipmi.c driver is the next candidate on my review list, and it appears that the driver has access to some alarm limits even if they've not been set by userland. Furthermore, it appears that the current driver uses these "built-in" alarm limits for setting the sensor state, overriding any limits that might be specified by the user.

The attached file contains an update to the ipmi(4) driver that will

1) expose the built-in limits to user-land (via envstat(8)), and
2) allow user-specified limits to override the built-in limits.

I don't have any ipmi hardware myself, to test these changes, so I'd appreciate it if someone who has ipmi would verify that these changes (a) don't break anything and hopefully (b) successfully implement features 1 & 2 above.


-------------------------------------------------------------------------
|   Paul Goyette   | PGP DSS Key fingerprint: |  E-mail addresses:      |
| Customer Service | FA29 0E3B 35AF E8AE 6651 |  paul at whooppee.com   |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer |                          | pgoyette at netbsd.org  |
-------------------------------------------------------------------------
Index: sys/arch/x86/x86/ipmi.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/ipmi.c,v
retrieving revision 1.35
diff -u -p -r1.35 ipmi.c
--- sys/arch/x86/x86/ipmi.c     1 Jun 2009 20:36:43 -0000       1.35
+++ sys/arch/x86/x86/ipmi.c     14 Jun 2009 19:27:58 -0000
@@ -89,6 +89,7 @@ struct ipmi_sensor {
        char            i_envdesc[64];
        int             i_envtype; /* envsys compatible type */
        int             i_envnum; /* envsys index */
+       sysmon_envsys_lim_t *i_limits;
        SLIST_ENTRY(ipmi_sensor) i_list;
 };
 
@@ -214,8 +215,11 @@ void       ipmi_unmap_regs(struct ipmi_softc *
 
 void   *scan_sig(long, long, int, int, const void *);
 
-int    ipmi_test_threshold_lo(uint8_t, uint8_t, uint8_t);
-int    ipmi_test_threshold_hi(uint8_t, uint8_t, uint8_t);
+int32_t        ipmi_convert_sensor(uint8_t *, struct ipmi_sensor *);
+void   ipmi_get_limits(struct sysmon_envsys *, envsys_data_t *,
+                       sysmon_envsys_lim_t *);
+int    ipmi_get_sensor_limits(struct ipmi_softc *, struct ipmi_sensor *,
+                              sysmon_envsys_lim_t *);
 int    ipmi_sensor_status(struct ipmi_softc *, struct ipmi_sensor *,
                           envsys_data_t *, uint8_t *);
 
@@ -1307,46 +1311,104 @@ ipmi_convert(uint8_t v, struct sdrtype1 
        return (val);
 }
 
-int
-ipmi_test_threshold_hi(uint8_t v, uint8_t valid, uint8_t hi)
-{
-       dbg_printf(10, "thresh_hi: %.2x %.2x %d\n", v, hi, valid);
-       return (valid & 8 && hi != 0xFF && v >= hi);
-}
-
-int
-ipmi_test_threshold_lo(uint8_t v, uint8_t valid, uint8_t lo)
-{
-       dbg_printf(10, "thresh_lo: %.2x %.2x %d\n", v, lo, valid);
-       return (valid & 1 && lo != 0x00 && v <= lo);
-}
-
-int
-ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
-    envsys_data_t *edata, uint8_t *reading)
+int32_t
+ipmi_convert_sensor(uint8_t *reading, struct ipmi_sensor *psensor)
 {
-       uint8_t data[32];
        struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
-       int             rxlen, etype;
-       /* Get reading of sensor */
-       switch (edata->units) {
+       int32_t val;
+
+       switch (psensor->i_envtype) {
        case ENVSYS_STEMP:
-               edata->value_cur = ipmi_convert(reading[0], s1, 6);
-               edata->value_cur += 273150000;
+               val = ipmi_convert(reading[0], s1, 6) + 273150000;
                break;
 
        case ENVSYS_SVOLTS_DC:
-               edata->value_cur = ipmi_convert(reading[0], s1, 6);
+               val = ipmi_convert(reading[0], s1, 6);
                break;
 
        case ENVSYS_SFANRPM:
-               edata->value_cur = ipmi_convert(reading[0], s1, 0);
+               val = ipmi_convert(reading[0], s1, 0);
                if (((s1->units1>>3)&0x7) == 0x3)
-                       edata->value_cur *= 60; /* RPS -> RPM */
+                       val *= 60; /* RPS -> RPM */
                break;
        default:
+               val = 0;
                break;
        }
+       return val;
+}
+
+void
+ipmi_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+               sysmon_envsys_lim_t *limits)
+{
+       struct ipmi_sensor *ipmi_s;
+       struct ipmi_softc *sc = sme->sme_cookie;
+
+       /* Find the ipmi_sensor corresponding to this edata */
+       SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
+               if (ipmi_s->i_envnum == edata->sensor) {
+                       (void)ipmi_get_sensor_limits(sc, ipmi_s, limits);
+                       ipmi_s->i_limits = limits;
+                       return;
+               }
+       }
+       return;
+}
+
+int
+ipmi_get_sensor_limits(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
+                      sysmon_envsys_lim_t *limits)
+{
+       struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
+       int     rxlen;
+       uint8_t data[32];
+
+       data[0] = psensor->i_num;
+       if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
+                        SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) ||
+           ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
+               return -1;
+
+       dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
+           data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
+
+       limits->sel_flags = 0;
+       if (data[0] & 0x20) {
+               limits->sel_critmax = ipmi_convert_sensor(&data[6], psensor);
+               limits->sel_flags |= PROP_CRITMAX;
+       }
+       if (data[0] & 0x10) {
+               limits->sel_critmax = ipmi_convert_sensor(&data[5], psensor);
+               limits->sel_flags |= PROP_CRITMAX;
+       }
+       if (data[0] & 0x08) {
+               limits->sel_warnmax = ipmi_convert_sensor(&data[4], psensor);
+               limits->sel_flags |= PROP_WARNMAX;
+       }
+       if (data[0] & 0x04) {
+               limits->sel_critmin = ipmi_convert_sensor(&data[3], psensor);
+               limits->sel_flags |= PROP_CRITMIN;
+       }
+       if (data[0] & 0x02) {
+               limits->sel_critmin = ipmi_convert_sensor(&data[2], psensor);
+               limits->sel_flags |= PROP_CRITMIN;
+       }
+       if (data[0] & 0x01) {
+               limits->sel_warnmin = ipmi_convert_sensor(&data[1], psensor);
+               limits->sel_flags |= PROP_WARNMIN;
+       }
+       return 0;
+}
+
+int
+ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
+    envsys_data_t *edata, uint8_t *reading)
+{
+       int     etype;
+
+       /* Get reading of sensor */
+       edata->value_cur = ipmi_convert_sensor(reading, psensor);
 
        /* Return Sensor Status */
        etype = (psensor->i_etype << 8) + psensor->i_stype;
@@ -1354,34 +1416,25 @@ ipmi_sensor_status(struct ipmi_softc *sc
        case IPMI_SENSOR_TYPE_TEMP:
        case IPMI_SENSOR_TYPE_VOLT:
        case IPMI_SENSOR_TYPE_FAN:
-               data[0] = psensor->i_num;
-               if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
-                   SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) ||
-                   ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
-                       return ENVSYS_SVALID;
-
-               dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
-                   data[0], data[1], data[2], data[3], data[4], data[5],
-                   data[6]);
-
-               if (ipmi_test_threshold_hi(*reading, data[0] >> 2 , data[6]))
-                       return ENVSYS_SCRITOVER;
+               if (psensor->i_limits == NULL)
+                       break;
 
-               if (ipmi_test_threshold_hi(*reading, data[0] >> 1, data[5]))
+               if (psensor->i_limits->sel_flags & PROP_CRITMAX &&
+                   edata->value_cur > psensor->i_limits->sel_critmax)
                        return ENVSYS_SCRITOVER;
 
-               if (ipmi_test_threshold_hi(*reading, data[0] , data[4]))
+               if (psensor->i_limits->sel_flags & PROP_WARNMAX &&
+                   edata->value_cur > psensor->i_limits->sel_warnmax)
                        return ENVSYS_SWARNOVER;
 
-               if (ipmi_test_threshold_lo(*reading, data[0] >> 2 , data[3]))
-                       return ENVSYS_SCRITUNDER;
+               if (psensor->i_limits->sel_flags & PROP_WARNMIN &&
+                   edata->value_cur > psensor->i_limits->sel_warnmin)
+                       return ENVSYS_SWARNUNDER;
 
-               if (ipmi_test_threshold_lo(*reading, data[0] >> 1, data[2]))
+               if (psensor->i_limits->sel_flags & PROP_CRITMIN &&
+                   edata->value_cur > psensor->i_limits->sel_critmin)
                        return ENVSYS_SCRITUNDER;
 
-               if (ipmi_test_threshold_lo(*reading, data[0] , data[1]))
-                       return ENVSYS_SWARNUNDER;
-
                break;
 
        case IPMI_SENSOR_TYPE_INTRUSION:
@@ -1775,18 +1828,26 @@ ipmi_thread(void *cookie)
                i = current_index_typ[ipmi_s->i_envtype];
                current_index_typ[ipmi_s->i_envtype]++;
                ipmi_s->i_envnum = i;
+               ipmi_s->i_limits = NULL;
                sc->sc_sensor[i].units = ipmi_s->i_envtype;
                sc->sc_sensor[i].state = ENVSYS_SINVALID;
                sc->sc_sensor[i].monitor = true;
                /*
                 * Monitor threshold limits in the sensors.
                 */
-               sc->sc_sensor[i].flags |= ENVSYS_FMONCRITICAL;
-               sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
+               switch (sc->sc_sensor[i].units) {
+               case ENVSYS_STEMP:
+               case ENVSYS_SVOLTS_DC:
+               case ENVSYS_SFANRPM:
+                       sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
+                       break;
+               default:
+                       sc->sc_sensor[i].flags |= ENVSYS_FMONCRITICAL;
+               }
                (void)strlcpy(sc->sc_sensor[i].desc, ipmi_s->i_envdesc,
                    sizeof(sc->sc_sensor[i].desc));
                if (sysmon_envsys_sensor_attach(sc->sc_envsys,
-                   &sc->sc_sensor[i]))
+                                               &sc->sc_sensor[i]))
                        continue;
        }
 


Home | Main Index | Thread Index | Old Index