root/arch/i386/i386/esm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. esm_probe
  2. esm_match
  3. esm_attach
  4. esm_watchdog
  5. esm_refresh
  6. esm_get_devmap
  7. esm_devmap
  8. esm_make_sensors
  9. esm_thresholds
  10. esm_bmc_ready
  11. esm_cmd
  12. esm_smb_cmd
  13. esm_val2temp
  14. esm_val2volts
  15. esm_val2amps

    1 /*      $OpenBSD: esm.c,v 1.46 2007/03/22 16:55:31 deraadt Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
    5  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/param.h>
   21 #include <sys/systm.h>
   22 #include <sys/device.h>
   23 #include <sys/kernel.h>
   24 #include <sys/malloc.h>
   25 #include <sys/timeout.h>
   26 #include <sys/proc.h>
   27 #include <sys/queue.h>
   28 #include <sys/sensors.h>
   29 
   30 #include <dev/isa/isareg.h>
   31 #include <machine/bus.h>
   32 #include <machine/intr.h>
   33 
   34 #include <arch/i386/i386/esmvar.h>
   35 #include <arch/i386/i386/esmreg.h>
   36 #include <arch/i386/isa/isa_machdep.h>
   37 
   38 #ifdef ESM_DEBUG
   39 #define DPRINTF(x...)           do { if (esmdebug) printf(x); } while (0)
   40 #define DPRINTFN(n,x...)        do { if (esmdebug > (n)) printf(x); } while (0)
   41 int     esmdebug = 3;
   42 #else
   43 #define DPRINTF(x...)           /* x */
   44 #define DPRINTFN(n,x...)        /* n: x */
   45 #endif
   46 
   47 int             esm_match(struct device *, void *, void *);
   48 void            esm_attach(struct device *, struct device *, void *);
   49 
   50 enum esm_sensor_type {
   51         ESM_S_UNKNOWN, /* XXX */
   52         ESM_S_INTRUSION,
   53         ESM_S_TEMP,
   54         ESM_S_FANRPM,
   55         ESM_S_VOLTS,
   56         ESM_S_VOLTSx10,
   57         ESM_S_AMPS,
   58         ESM_S_PWRSUP,
   59         ESM_S_PCISLOT,
   60         ESM_S_SCSICONN,
   61         ESM_S_DRIVES, /* argument is the base index of the drive */
   62         ESM_S_DRIVE,
   63         ESM_S_HPSLOT,
   64         ESM_S_ACSWITCH
   65 };
   66 
   67 /*
   68  * map esm sensor types to kernel sensor types.
   69  * keep this in sync with the esm_sensor_type enum above.
   70  */
   71 enum sensor_type esm_typemap[] = {
   72         SENSOR_INTEGER,
   73         SENSOR_INDICATOR,
   74         SENSOR_TEMP,
   75         SENSOR_FANRPM,
   76         SENSOR_VOLTS_DC,
   77         SENSOR_VOLTS_DC,
   78         SENSOR_AMPS,
   79         SENSOR_INDICATOR,
   80         SENSOR_INTEGER,
   81         SENSOR_INDICATOR,
   82         SENSOR_DRIVE,
   83         SENSOR_DRIVE,
   84         SENSOR_INTEGER,
   85         SENSOR_INDICATOR
   86 };
   87 
   88 struct esm_sensor_map {
   89         enum esm_sensor_type    type;
   90         long                    arg;
   91         const char              *name;
   92 };
   93 
   94 struct esm_sensor {
   95         u_int8_t                es_dev;
   96         u_int8_t                es_id;
   97 
   98         enum esm_sensor_type    es_type;
   99 
  100         struct {
  101                 u_int16_t               th_lo_crit;
  102                 u_int16_t               th_lo_warn;
  103                 u_int16_t               th_hi_warn;
  104                 u_int16_t               th_hi_crit;
  105         }                       es_thresholds;
  106 
  107         struct ksensor          *es_sensor;
  108         TAILQ_ENTRY(esm_sensor) es_entry;
  109 };
  110 
  111 struct esm_softc {
  112         struct device           sc_dev;
  113         bus_space_tag_t         sc_iot;
  114         bus_space_handle_t      sc_ioh;
  115 
  116         TAILQ_HEAD(, esm_sensor) sc_sensors;
  117         struct esm_sensor       *sc_nextsensor;
  118         struct ksensordev       sc_sensordev;
  119         int                     sc_retries;
  120         volatile int            sc_step;
  121         struct timeout          sc_timeout;
  122 
  123         int                     sc_wdog_period;
  124         volatile int            sc_wdog_tickle;
  125 };
  126 
  127 struct cfattach esm_ca = {
  128         sizeof(struct esm_softc), esm_match, esm_attach
  129 };
  130 
  131 struct cfdriver esm_cd = {
  132         NULL, "esm", DV_DULL
  133 };
  134 
  135 #define DEVNAME(s)      ((s)->sc_dev.dv_xname)
  136 
  137 #define EREAD(s, r)     bus_space_read_1((s)->sc_iot, (s)->sc_ioh, (r))
  138 #define EWRITE(s, r, v) bus_space_write_1((s)->sc_iot, (s)->sc_ioh, (r), (v))
  139 
  140 #define ECTRLWR(s, v)   EWRITE((s), ESM2_CTRL_REG, (v))
  141 #define EDATARD(s)      EREAD((s), ESM2_DATA_REG)
  142 #define EDATAWR(s, v)   EWRITE((s), ESM2_DATA_REG, (v))
  143 
  144 int             esm_watchdog(void *, int);
  145 
  146 void            esm_refresh(void *);
  147 
  148 int             esm_get_devmap(struct esm_softc *, int, struct esm_devmap *);
  149 void            esm_devmap(struct esm_softc *, struct esm_devmap *);
  150 void            esm_make_sensors(struct esm_softc *, struct esm_devmap *,
  151                     struct esm_sensor_map *, int);
  152 int             esm_thresholds(struct esm_softc *, struct esm_devmap *,
  153                     struct esm_sensor *);
  154 
  155 int             esm_bmc_ready(struct esm_softc *, int, u_int8_t, u_int8_t, int);
  156 int             esm_cmd(struct esm_softc *, void *, size_t, void *, size_t,
  157                     int, int);
  158 int             esm_smb_cmd(struct esm_softc *, struct esm_smb_req *,
  159                     struct esm_smb_resp *, int, int);
  160 
  161 int64_t         esm_val2temp(u_int16_t);
  162 int64_t         esm_val2volts(u_int16_t);
  163 int64_t         esm_val2amps(u_int16_t);
  164 
  165 /* Determine if this is a Dell server */
  166 int
  167 esm_probe(void *aux)
  168 {
  169         const char *pdellstr;
  170         struct dell_sysid *pdellid;
  171         uint16_t sysid;
  172 
  173         pdellstr = (const char *)ISA_HOLE_VADDR(DELL_SYSSTR_ADDR);
  174         DPRINTF("Dell String: %s\n", pdellstr);
  175         if (strncmp(pdellstr, "Dell System", 11))
  176                 return (0);
  177 
  178         pdellid = (struct dell_sysid *)ISA_HOLE_VADDR(DELL_SYSID_ADDR);
  179         if ((sysid = pdellid->sys_id) == DELL_SYSID_EXT)
  180                 sysid = pdellid->ext_id;
  181         DPRINTF("SysId: %x\n", sysid);
  182 
  183         switch (sysid) {
  184         case DELL_SYSID_2300:
  185         case DELL_SYSID_4300:
  186         case DELL_SYSID_4350:
  187         case DELL_SYSID_6300:
  188         case DELL_SYSID_6350:
  189         case DELL_SYSID_2400:
  190         case DELL_SYSID_2450:
  191         case DELL_SYSID_4400:
  192         case DELL_SYSID_6400:
  193         case DELL_SYSID_6450:
  194         case DELL_SYSID_2500:
  195         case DELL_SYSID_2550:
  196         case DELL_SYSID_PV530F:
  197         case DELL_SYSID_PV735N:
  198         case DELL_SYSID_PV750N:
  199         case DELL_SYSID_PV755N:
  200         case DELL_SYSID_PA200:
  201                 return (1);
  202         }
  203 
  204         return (0);
  205 }
  206 
  207 int
  208 esm_match(struct device *parent, void *match, void *aux)
  209 {
  210         struct esm_attach_args          *eaa = aux;
  211 
  212         if (strncmp(eaa->eaa_name, esm_cd.cd_name, sizeof(esm_cd.cd_name)) == 0 &&
  213             esm_probe(eaa))
  214                 return (1);
  215 
  216         return (0);
  217 }
  218 
  219 void
  220 esm_attach(struct device *parent, struct device *self, void *aux)
  221 {
  222         struct esm_softc                *sc = (struct esm_softc *)self;
  223         struct esm_attach_args          *eaa = aux;
  224         u_int8_t                        x;
  225 
  226         struct esm_devmap               devmap;
  227         int                             i;
  228 
  229         sc->sc_iot = eaa->eaa_iot;
  230         TAILQ_INIT(&sc->sc_sensors);
  231 
  232         if (bus_space_map(sc->sc_iot, ESM2_BASE_PORT, 8, 0, &sc->sc_ioh) != 0) {
  233                 printf(": unable to map memory\n");
  234                 return;
  235         }
  236 
  237         /* turn off interrupts here */
  238         x = EREAD(sc, ESM2_INTMASK_REG);
  239         x &= ~(ESM2_TIM_SCI_EN|ESM2_TIM_SMI_EN|ESM2_TIM_NMI2SMI);
  240         x |= ESM2_TIM_POWER_UP_BITS;
  241         EWRITE(sc, ESM2_INTMASK_REG, x);
  242 
  243         /* clear event doorbells */
  244         x = EREAD(sc, ESM2_CTRL_REG);
  245         x &= ~ESM2_TC_HOSTBUSY;
  246         x |= ESM2_TC_POWER_UP_BITS;
  247         EWRITE(sc, ESM2_CTRL_REG, x);
  248 
  249         /* see if card is alive */
  250         if (esm_bmc_ready(sc, ESM2_CTRL_REG, ESM2_TC_ECBUSY, 0, 1) != 0) {
  251                 printf(": card is not alive\n");
  252                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 8);
  253                 return;
  254         }
  255 
  256         sc->sc_wdog_period = 0;
  257         wdog_register(sc, esm_watchdog);
  258         printf("\n");
  259 
  260         strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
  261             sizeof(sc->sc_sensordev.xname));
  262         for (i = 0; i <= 0xff; i++) {
  263                 if (esm_get_devmap(sc, i, &devmap) != 0)
  264                         break; /* XXX not continue? */
  265                 esm_devmap(sc, &devmap);
  266         }
  267 
  268         if (!TAILQ_EMPTY(&sc->sc_sensors)) {
  269                 sensordev_install(&sc->sc_sensordev);
  270                 DPRINTF("%s: starting refresh\n", DEVNAME(sc));
  271                 sc->sc_nextsensor = TAILQ_FIRST(&sc->sc_sensors);
  272                 sc->sc_retries = 0;
  273                 timeout_set(&sc->sc_timeout, esm_refresh, sc);
  274                 timeout_add(&sc->sc_timeout, hz);
  275         }
  276 }
  277 
  278 int
  279 esm_watchdog(void *arg, int period)
  280 {
  281         struct esm_softc        *sc = arg;
  282         struct esm_wdog_prop    prop;
  283         struct esm_wdog_state   state;
  284         int                     s;
  285 
  286         if (sc->sc_wdog_period == period) {
  287                 if (period != 0) {
  288                         s = splclock();
  289                         if (sc->sc_step != 0) {
  290                                 /* defer tickling to the sensor refresh */
  291                                 sc->sc_wdog_tickle = 1;
  292                         } else {
  293                                 /* tickle the watchdog */
  294                                 EWRITE(sc, ESM2_CTRL_REG, ESM2_TC_HBDB);
  295                         }
  296                         splx(s);
  297                 }
  298                 return (period);
  299         }
  300 
  301         /* we're changing the watchdog period */
  302 
  303         memset(&prop, 0, sizeof(prop));
  304         memset(&state, 0, sizeof(state));
  305 
  306         if (period < 10 && period > 0)
  307                 period = 10;
  308 
  309         s = splclock();
  310 
  311         prop.cmd = ESM2_CMD_HWDC;
  312         prop.subcmd = ESM2_HWDC_WRITE_PROPERTY;
  313         prop.action = (period == 0) ? ESM_WDOG_DISABLE : ESM_WDOG_RESET;
  314         prop.time = period;
  315 
  316         /*
  317          * if we're doing a refresh, we need to wait till the hardware is
  318          * available again. since period changes only happen via sysctl we
  319          * should have a process context we can sleep in.
  320          */
  321         while (sc->sc_step != 0) {
  322                 if (tsleep(sc, PUSER | PCATCH, "esm", 0) == EINTR) {
  323                         splx(s);
  324                         return (sc->sc_wdog_period);
  325                 }
  326         }
  327 
  328         if (esm_cmd(sc, &prop, sizeof(prop), NULL, 0, 1, 0) != 0) {
  329                 splx(s);
  330                 return (sc->sc_wdog_period);
  331         }
  332 
  333         state.cmd = ESM2_CMD_HWDC;
  334         state.subcmd = ESM2_HWDC_WRITE_STATE;
  335         state.state = (period == 0) ? 0 : 1;
  336 
  337         /* we have the hw, this can't (shouldn't) fail */
  338         esm_cmd(sc, &state, sizeof(state), NULL, 0, 1, 0);
  339 
  340         splx(s);
  341 
  342         sc->sc_wdog_period = period;
  343         return (period);
  344 }
  345 
  346 void
  347 esm_refresh(void *arg)
  348 {
  349         struct esm_softc        *sc = arg;
  350         struct esm_sensor       *es = sc->sc_nextsensor;
  351         struct esm_smb_req      req;
  352         struct esm_smb_resp     resp;
  353         struct esm_smb_resp_val *val = &resp.resp_val;
  354         int                     nsensors, i, step;
  355 
  356         memset(&req, 0, sizeof(req));
  357         req.h_cmd = ESM2_CMD_SMB_XMIT_RECV;
  358         req.h_dev = es->es_dev;
  359         req.h_txlen = sizeof(req.req_val);
  360         req.h_rxlen = sizeof(resp.resp_val);
  361         req.req_val.v_cmd = ESM2_SMB_SENSOR_VALUE;
  362         req.req_val.v_sensor = es->es_id;
  363 
  364         switch (es->es_type) {
  365         case ESM_S_DRIVES:
  366                 nsensors = 4;
  367                 break;
  368         case ESM_S_PWRSUP:
  369                 nsensors = 6;
  370                 break;
  371         default:
  372                 nsensors = 1;
  373                 break;
  374         }
  375 
  376         if ((step = esm_smb_cmd(sc, &req, &resp, 0, sc->sc_step)) != 0) {
  377                 sc->sc_step = step;
  378                 if (++sc->sc_retries < 10)
  379                         goto tick;
  380 
  381                 for (i = 0; i < nsensors; i++)
  382                         es->es_sensor[i].flags |= SENSOR_FINVALID;
  383         } else {
  384                 switch (es->es_type) {
  385                 case ESM_S_TEMP:
  386                         es->es_sensor->value = esm_val2temp(val->v_reading);
  387                         break;
  388                 case ESM_S_VOLTS:
  389                         es->es_sensor->value = esm_val2volts(val->v_reading);
  390                         break;
  391                 case ESM_S_VOLTSx10:
  392                         es->es_sensor->value =
  393                             esm_val2volts(val->v_reading) * 10;
  394                         break;
  395                 case ESM_S_AMPS:
  396                         es->es_sensor->value = esm_val2amps(val->v_reading);
  397                         break;
  398                 case ESM_S_DRIVES:
  399                         for (i = 0; i < nsensors; i++) {
  400                                 es->es_sensor[i].value =
  401                                     (val->v_reading >> i * 8) & 0xf;
  402                         }
  403                         break;
  404                 case ESM_S_PWRSUP:
  405                         for (i = 0; i < nsensors; i++) {
  406                                 es->es_sensor[i].value =
  407                                     (val->v_reading >> i) & 0x1;
  408                         }
  409                         break;
  410                 default:
  411                         es->es_sensor->value = val->v_reading;
  412                         break;
  413                 }
  414 
  415                 switch (es->es_type) {
  416                 case ESM_S_TEMP:
  417                 case ESM_S_FANRPM:
  418                 case ESM_S_VOLTS:
  419                 case ESM_S_AMPS:
  420                         if (val->v_reading >= es->es_thresholds.th_hi_crit ||
  421                             val->v_reading <= es->es_thresholds.th_lo_crit) {
  422                                 es->es_sensor->status = SENSOR_S_CRIT;
  423                                 break;
  424                         }
  425 
  426                         if (val->v_reading >= es->es_thresholds.th_hi_warn ||
  427                             val->v_reading <= es->es_thresholds.th_lo_warn) {
  428                                 es->es_sensor->status = SENSOR_S_WARN;
  429                                 break;
  430                         }
  431 
  432                         es->es_sensor->status = SENSOR_S_OK;
  433                         break;
  434 
  435                 case ESM_S_PWRSUP:
  436                         if (val->v_status & ESM2_VS_PSU_FAIL) {
  437                                 es->es_sensor[3].status = SENSOR_S_CRIT;
  438                                 break;
  439                         }
  440 
  441                         es->es_sensor[3].status = SENSOR_S_OK;
  442                         break;
  443 
  444                 default:
  445                         break;
  446                 }
  447 
  448                 for (i = 0; i < nsensors; i++)
  449                         es->es_sensor->flags &= ~SENSOR_FINVALID;
  450         }
  451 
  452         sc->sc_nextsensor = TAILQ_NEXT(es, es_entry);
  453         sc->sc_retries = 0;
  454         sc->sc_step = 0;
  455 
  456         if (sc->sc_wdog_tickle) {
  457                 /*
  458                  * the controller was busy in a refresh when the watchdog
  459                  * needed a tickle, so do it now.
  460                  */
  461                 EWRITE(sc, ESM2_CTRL_REG, ESM2_TC_HBDB);
  462                 sc->sc_wdog_tickle = 0;
  463         }
  464         wakeup(sc);
  465 
  466         if (sc->sc_nextsensor == NULL) {
  467                 sc->sc_nextsensor = TAILQ_FIRST(&sc->sc_sensors);
  468                 timeout_add(&sc->sc_timeout, hz * 10);
  469                 return;
  470         }
  471 tick:
  472         timeout_add(&sc->sc_timeout, hz / 20);
  473 }
  474 
  475 int
  476 esm_get_devmap(struct esm_softc *sc, int dev, struct esm_devmap *devmap)
  477 {
  478         struct esm_devmap_req   req;
  479         struct esm_devmap_resp  resp;
  480 #ifdef ESM_DEBUG
  481         int                     i;
  482 #endif
  483 
  484         memset(&req, 0, sizeof(req));
  485         memset(&resp, 0, sizeof(resp));
  486 
  487         req.cmd = ESM2_CMD_DEVICEMAP;
  488         req.action = ESM2_DEVICEMAP_READ;
  489         req.index = dev;
  490         req.ndev = 1;
  491 
  492         if (esm_cmd(sc, &req, sizeof(req), &resp, sizeof(resp), 1, 0) != 0)
  493                 return (1);
  494 
  495         if (resp.status != 0)
  496                 return (1);
  497 
  498         memcpy(devmap, &resp.devmap[0], sizeof(struct esm_devmap));
  499 
  500 #ifdef ESM_DEBUG
  501         if (esmdebug > 5) {
  502                 printf("\n");
  503                 printf("Device Map(%d) returns:\n", dev);
  504                 printf("  status: %.2x\n", resp.status);
  505                 printf("  #devs : %.2x\n", resp.ndev);
  506                 printf("   index: %.2x\n", resp.devmap[0].index);
  507                 printf("   Type : %.2x.%.2x\n", resp.devmap[0].dev_major,
  508                     resp.devmap[0].dev_minor);
  509                 printf("   Rev  : %.2x.%.2x\n", resp.devmap[0].rev_major,
  510                     resp.devmap[0].rev_minor);
  511                 printf("   ROM  : %.2x\n", resp.devmap[0].rev_rom);
  512                 printf("   SMB  : %.2x\n", resp.devmap[0].smb_addr);
  513                 printf("   Stat : %.2x\n", resp.devmap[0].status);
  514                 printf("   MonTy: %.2x\n", resp.devmap[0].monitor_type);
  515                 printf("   Poll : %.2x\n", resp.devmap[0].pollcycle);
  516                 printf("   UUID : ");
  517                 for (i = 0; i < ESM2_UUID_LEN; i++) {
  518                         printf("%02x", resp.devmap[0].uniqueid[i]);
  519                 }
  520                 printf("\n");
  521         }
  522 #endif /* ESM_DEBUG */
  523 
  524         return (0);
  525 }
  526 
  527 struct esm_sensor_map esm_sensors_esm2[] = {
  528         { ESM_S_UNKNOWN,        0,              "Motherboard" },
  529         { ESM_S_TEMP,           0,              "CPU 1" },
  530         { ESM_S_TEMP,           0,              "CPU 2" },
  531         { ESM_S_TEMP,           0,              "CPU 3" },
  532         { ESM_S_TEMP,           0,              "CPU 4" },
  533 
  534         { ESM_S_TEMP,           0,              "Mainboard" },
  535         { ESM_S_TEMP,           0,              "Ambient" },
  536         { ESM_S_VOLTS,          0,              "CPU 1 Core" },
  537         { ESM_S_VOLTS,          0,              "CPU 2 Core" },
  538         { ESM_S_VOLTS,          0,              "CPU 3 Core" },
  539 
  540         { ESM_S_VOLTS,          0,              "CPU 4 Core" },
  541         { ESM_S_VOLTS,          0,              "Motherboard +5V" },
  542         { ESM_S_VOLTS,          0,              "Motherboard +12V" },
  543         { ESM_S_VOLTS,          0,              "Motherboard +3.3V" },
  544         { ESM_S_VOLTS,          0,              "Motherboard +2.5V" },
  545 
  546         { ESM_S_VOLTS,          0,              "Motherboard GTL Term" },
  547         { ESM_S_VOLTS,          0,              "Motherboard Battery" },
  548         { ESM_S_INTRUSION,      0,              "Chassis Intrusion", },
  549         { ESM_S_UNKNOWN,        0,              "Chassis Fan Ctrl", },
  550         { ESM_S_FANRPM,         0,              "Fan 1" },
  551 
  552         { ESM_S_FANRPM,         0,              "Fan 2" }, /* 20 */
  553         { ESM_S_FANRPM,         0,              "Fan 3" },
  554         { ESM_S_FANRPM,         0,              "Power Supply Fan" },
  555         { ESM_S_VOLTS,          0,              "CPU 1 cache" },
  556         { ESM_S_VOLTS,          0,              "CPU 2 cache" },
  557 
  558         { ESM_S_VOLTS,          0,              "CPU 3 cache" },
  559         { ESM_S_VOLTS,          0,              "CPU 4 cache" },
  560         { ESM_S_UNKNOWN,        0,              "Power Ctrl" },
  561         { ESM_S_PWRSUP,         0,              "Power Supply 1" },
  562         { ESM_S_PWRSUP,         0,              "Power Supply 2" },
  563 
  564         { ESM_S_VOLTS,          0,              "Mainboard +1.5V" }, /* 30 */
  565         { ESM_S_VOLTS,          0,              "Motherboard +2.8V" },
  566         { ESM_S_UNKNOWN,        0,              "HotPlug Status" },
  567         { ESM_S_PCISLOT,        0,              "PCI Slot 1" },
  568         { ESM_S_PCISLOT,        0,              "PCI Slot 2" },
  569 
  570         { ESM_S_PCISLOT,        0,              "PCI Slot 3" },
  571         { ESM_S_PCISLOT,        0,              "PCI Slot 4" },
  572         { ESM_S_PCISLOT,        0,              "PCI Slot 5" },
  573         { ESM_S_PCISLOT,        0,              "PCI Slot 6" },
  574         { ESM_S_PCISLOT,        0,              "PCI Slot 7" },
  575 
  576         { ESM_S_VOLTS,          0,              "CPU 1 Cartridge" }, /* 40 */
  577         { ESM_S_VOLTS,          0,              "CPU 2 Cartridge" },
  578         { ESM_S_VOLTS,          0,              "CPU 3 Cartridge" },
  579         { ESM_S_VOLTS,          0,              "CPU 4 Cartridge" },
  580         { ESM_S_VOLTS,          0,              "Gigabit NIC +1.8V" },
  581 
  582         { ESM_S_VOLTS,          0,              "Gigabit NIC +2.5V" },
  583         { ESM_S_VOLTS,          0,              "Memory +3.3V" },
  584         { ESM_S_VOLTS,          0,              "Video +2.5V" },
  585         { ESM_S_PWRSUP,         0,              "Power Supply 3" },
  586         { ESM_S_FANRPM,         0,              "Fan 4" },
  587 
  588         { ESM_S_FANRPM,         0,              "Power Supply Fan" }, /* 50 */
  589         { ESM_S_FANRPM,         0,              "Power Supply Fan" },
  590         { ESM_S_FANRPM,         0,              "Power Supply Fan" },
  591         { ESM_S_ACSWITCH,       0,              "A/C Power Switch" },
  592         { ESM_S_UNKNOWN,        0,              "PS Over Temp" }
  593 };
  594 
  595 struct esm_sensor_map esm_sensors_backplane[] = {
  596         { ESM_S_UNKNOWN,        0,              "Backplane" },
  597         { ESM_S_UNKNOWN,        0,              "Backplane Control" },
  598         { ESM_S_TEMP,           0,              "Backplane Top" },
  599         { ESM_S_TEMP,           0,              "Backplane Bottom" },
  600         { ESM_S_TEMP,           0,              "Backplane Control Panel" },
  601         { ESM_S_VOLTS,          0,              "Backplane Battery" },
  602         { ESM_S_VOLTS,          0,              "Backplane +5V" },
  603         { ESM_S_VOLTS,          0,              "Backplane +12V" },
  604         { ESM_S_VOLTS,          0,              "Backplane Board" },
  605         { ESM_S_INTRUSION,      0,              "Backplane Intrusion" },
  606         { ESM_S_UNKNOWN,        0,              "Backplane Fan Control" },
  607         { ESM_S_FANRPM,         0,              "Backplane Fan 1" },
  608         { ESM_S_FANRPM,         0,              "Backplane Fan 2" },
  609         { ESM_S_FANRPM,         0,              "Backplane Fan 3" },
  610         { ESM_S_SCSICONN,       0,              "Backplane SCSI A Connected" },
  611         { ESM_S_VOLTS,          0,              "Backplane SCSI A External" },
  612         { ESM_S_VOLTS,          0,              "Backplane SCSI A Internal" },
  613         { ESM_S_SCSICONN,       0,              "Backplane SCSI B Connected" },
  614         { ESM_S_VOLTS,          0,              "Backplane SCSI B External" },
  615         { ESM_S_VOLTS,          0,              "Backplane SCSI B Internal" },
  616         { ESM_S_DRIVES,         0,              "Drive" },
  617         { ESM_S_DRIVES,         4,              "Drive" },
  618         { ESM_S_DRIVE,          0,              "Drive 0" },
  619         { ESM_S_DRIVE,          0,              "Drive 1" },
  620         { ESM_S_DRIVE,          0,              "Drive 2" },
  621         { ESM_S_DRIVE,          0,              "Drive 3" },
  622         { ESM_S_DRIVE,          0,              "Drive 4" },
  623         { ESM_S_DRIVE,          0,              "Drive 5" },
  624         { ESM_S_DRIVE,          0,              "Drive 6" },
  625         { ESM_S_DRIVE,          0,              "Drive 7" },
  626         { ESM_S_UNKNOWN,        0,              "Backplane Control 2" },
  627         { ESM_S_VOLTS,          0,              "Backplane +3.3V" },
  628 };
  629 
  630 struct esm_sensor_map esm_sensors_powerunit[] = {
  631         { ESM_S_UNKNOWN,        0,              "Power Unit" },
  632         { ESM_S_VOLTSx10,       0,              "Power Supply 1 +5V" },
  633         { ESM_S_VOLTSx10,       0,              "Power Supply 1 +12V" },
  634         { ESM_S_VOLTSx10,       0,              "Power Supply 1 +3.3V" },
  635         { ESM_S_VOLTSx10,       0,              "Power Supply 1 -5V" },
  636 
  637         { ESM_S_VOLTSx10,       0,              "Power Supply 1 -12V" },
  638         { ESM_S_VOLTSx10,       0,              "Power Supply 2 +5V" },
  639         { ESM_S_VOLTSx10,       0,              "Power Supply 2 +12V" },
  640         { ESM_S_VOLTSx10,       0,              "Power Supply 2 +3.3V" },
  641         { ESM_S_VOLTSx10,       0,              "Power Supply 2 -5V" },
  642 
  643         { ESM_S_VOLTSx10,       0,              "Power Supply 2 -12V" },
  644         { ESM_S_VOLTSx10,       0,              "Power Supply 3 +5V" },
  645         { ESM_S_VOLTSx10,       0,              "Power Supply 3 +12V" },
  646         { ESM_S_VOLTSx10,       0,              "Power Supply 3 +3.3V" },
  647         { ESM_S_VOLTSx10,       0,              "Power Supply 3 -5V" },
  648 
  649         { ESM_S_VOLTSx10,       0,              "Power Supply 3 -12V" },
  650         { ESM_S_VOLTSx10,       0,              "System Power Supply +5V" },
  651         { ESM_S_VOLTSx10,       0,              "System Power Supply +12V" },
  652         { ESM_S_VOLTSx10,       0,              "System Power Supply +3.3V" },
  653         { ESM_S_VOLTSx10,       0,              "System Power Supply -5V" },
  654 
  655         { ESM_S_VOLTSx10,       0,              "System Power Supply -12V" },
  656         { ESM_S_VOLTSx10,       0,              "System Power Supply +5V aux" },
  657         { ESM_S_AMPS,           0,              "Power Supply 1 +5V" },
  658         { ESM_S_AMPS,           0,              "Power Supply 1 +12V" },
  659         { ESM_S_AMPS,           0,              "Power Supply 1 +3.3V" },
  660 
  661         { ESM_S_AMPS,           0,              "Power Supply 2 +5V" },
  662         { ESM_S_AMPS,           0,              "Power Supply 2 +12V" },
  663         { ESM_S_AMPS,           0,              "Power Supply 2 +3.3V" },
  664         { ESM_S_AMPS,           0,              "Power Supply 3 +5V" },
  665         { ESM_S_AMPS,           0,              "Power Supply 3 +12V" },
  666 
  667         { ESM_S_AMPS,           0,              "Power Supply 3 +3.3V" },
  668         { ESM_S_FANRPM,         0,              "Power Supply 1 Fan" },
  669         { ESM_S_FANRPM,         0,              "Power Supply 2 Fan" },
  670         { ESM_S_FANRPM,         0,              "Power Supply 3 Fan" },
  671         { ESM_S_PWRSUP,         0,              "Power Supply 1" },
  672 
  673         { ESM_S_PWRSUP,         0,              "Power Supply 2" },
  674         { ESM_S_PWRSUP,         0,              "Power Supply 3" },
  675         { ESM_S_UNKNOWN,        0,              "PSPB Fan Control" },
  676         { ESM_S_FANRPM,         0,              "Fan 1" },
  677         { ESM_S_FANRPM,         0,              "Fan 2" },
  678 
  679         { ESM_S_FANRPM,         0,              "Fan 3" },
  680         { ESM_S_FANRPM,         0,              "Fan 4" },
  681         { ESM_S_FANRPM,         0,              "Fan 5" },
  682         { ESM_S_FANRPM,         0,              "Fan 6" },
  683         { ESM_S_UNKNOWN,        0,              "Fan Enclosure" },
  684 };
  685 
  686 void
  687 esm_devmap(struct esm_softc *sc, struct esm_devmap *devmap)
  688 {
  689         struct esm_sensor_map   *sensor_map;
  690         const char              *name = NULL, *fname = NULL;
  691         int                     mapsize;
  692 
  693         switch (devmap->dev_major) {
  694         case ESM2_DEV_ESM2:
  695                 sensor_map = esm_sensors_esm2;
  696 
  697                 switch (devmap->dev_minor) {
  698                 case ESM2_DEV_ESM2_2300:
  699                         name = "PowerEdge 2300";
  700                         mapsize = 23;
  701                         break;
  702                 case ESM2_DEV_ESM2_4300:
  703                         name = "PowerEdge 4300";
  704                         mapsize = 27;
  705                         break;
  706                 case ESM2_DEV_ESM2_6300:
  707                         name = "PowerEdge 6300";
  708                         mapsize = 27;
  709                         break;
  710                 case ESM2_DEV_ESM2_6400:
  711                         name = "PowerEdge 6400";
  712                         mapsize = 44;
  713                         break;
  714                 case ESM2_DEV_ESM2_2550:
  715                         name = "PowerEdge 2550";
  716                         mapsize = 48;
  717                         break;
  718                 case ESM2_DEV_ESM2_4350:
  719                         name = "PowerEdge 4350";
  720                         mapsize = 27;
  721                         break;
  722                 case ESM2_DEV_ESM2_6350:
  723                         name = "PowerEdge 6350";
  724                         mapsize = 27;
  725                         break;
  726                 case ESM2_DEV_ESM2_6450:
  727                         name = "PowerEdge 6450";
  728                         mapsize = 44;
  729                         break;
  730                 case ESM2_DEV_ESM2_2400:
  731                         name = "PowerEdge 2400";
  732                         mapsize = 30;
  733                         break;
  734                 case ESM2_DEV_ESM2_4400:
  735                         name = "PowerEdge 4400";
  736                         mapsize = 44;
  737                         break;
  738                 case ESM2_DEV_ESM2_2500:
  739                         name = "PowerEdge 2500";
  740                         mapsize = 55;
  741                         break;
  742                 case ESM2_DEV_ESM2_2450:
  743                         name = "PowerEdge 2450";
  744                         mapsize = 27;
  745                         break;
  746                 case ESM2_DEV_ESM2_2400EX:
  747                         name = "PowerEdge 2400";
  748                         mapsize = 27;
  749                         break;
  750                 case ESM2_DEV_ESM2_2450EX:
  751                         name = "PowerEdge 2450";
  752                         mapsize = 44;
  753                         break;
  754                 default:
  755                         return;
  756                 }
  757 
  758                 fname = "Embedded Server Management";
  759                 break;
  760 
  761         case ESM2_DEV_DRACII:
  762                 fname = "Dell Remote Assistance Card II";
  763                 break;
  764 
  765         case ESM2_DEV_FRONT_PANEL:
  766                 fname = "Front Panel";
  767                 break;
  768 
  769         case ESM2_DEV_BACKPLANE2:
  770                 sensor_map = esm_sensors_backplane;
  771                 mapsize = 22;
  772 
  773                 fname = "Primary System Backplane";
  774                 break;
  775 
  776         case ESM2_DEV_POWERUNIT2:
  777                 sensor_map = esm_sensors_powerunit;
  778                 mapsize = sizeof(esm_sensors_powerunit) /
  779                     sizeof(esm_sensors_powerunit[0]);
  780 
  781                 fname = "Power Unit";
  782                 break;
  783 
  784         case ESM2_DEV_ENCL2_BACKPLANE:
  785         case ESM2_DEV_ENCL1_BACKPLANE:
  786                 fname = "Enclosure Backplane";
  787                 break;
  788 
  789         case ESM2_DEV_ENCL2_POWERUNIT:
  790         case ESM2_DEV_ENCL1_POWERUNIT:
  791                 fname = "Enclosure Powerunit";
  792                 break;
  793 
  794         case ESM2_DEV_HPPCI: /* nfi what this is */
  795                 fname = "HPPCI";
  796                 break;
  797 
  798         case ESM2_DEV_BACKPLANE3:
  799                 sensor_map = esm_sensors_backplane;
  800                 mapsize = sizeof(esm_sensors_backplane) /
  801                     sizeof(esm_sensors_backplane[0]);
  802 
  803                 fname = "Primary System Backplane";
  804                 break;
  805 
  806         default:
  807                 return;
  808         }
  809 
  810         printf("%s: %s%s%s %d.%d\n", DEVNAME(sc),
  811             name ? name : "", name ? " " : "", fname,
  812             devmap->rev_major, devmap->rev_minor);
  813 
  814         esm_make_sensors(sc, devmap, sensor_map, mapsize);
  815 }
  816 
  817 void
  818 esm_make_sensors(struct esm_softc *sc, struct esm_devmap *devmap,
  819     struct esm_sensor_map *sensor_map, int mapsize)
  820 {
  821         struct esm_smb_req      req;
  822         struct esm_smb_resp     resp;
  823         struct esm_smb_resp_val *val = &resp.resp_val;
  824         struct esm_sensor       *es;
  825         struct ksensor          *s;
  826         int                     nsensors, i, j;
  827         const char              *psulabels[] = {
  828                                     "AC", "SW", "OK", "ON", "FFAN", "OTMP"
  829                                 };
  830 
  831         memset(&req, 0, sizeof(req));
  832         req.h_cmd = ESM2_CMD_SMB_XMIT_RECV;
  833         req.h_dev = devmap->index;
  834         req.h_txlen = sizeof(req.req_val);
  835         req.h_rxlen = sizeof(resp.resp_val);
  836 
  837         req.req_val.v_cmd = ESM2_SMB_SENSOR_VALUE;
  838 
  839         for (i = 0; i < mapsize; i++) {
  840                 req.req_val.v_sensor = i;
  841                 if (esm_smb_cmd(sc, &req, &resp, 1, 0) != 0)
  842                         continue;
  843 
  844                 DPRINTFN(1, "%s: dev: 0x%02x sensor: %d (%s) "
  845                     "reading: 0x%04x status: 0x%02x cksum: 0x%02x\n",
  846                     DEVNAME(sc), devmap->index, i, sensor_map[i].name,
  847                     val->v_reading, val->v_status, val->v_checksum);
  848 
  849                 switch (sensor_map[i].type) {
  850                 case ESM_S_PWRSUP:
  851                         if (val->v_status == 0x00)
  852                                 continue;
  853                         break;
  854                 default:
  855                         if (!(val->v_status & ESM2_VS_VALID))
  856                                 continue;
  857                         break;
  858                 }
  859 
  860                 es = malloc(sizeof(struct esm_sensor), M_DEVBUF, M_NOWAIT);
  861                 if (es == NULL)
  862                         return;
  863 
  864                 memset(es, 0, sizeof(struct esm_sensor));
  865                 es->es_dev = devmap->index;
  866                 es->es_id = i;
  867                 es->es_type = sensor_map[i].type;
  868 
  869                 switch (es->es_type) {
  870                 case ESM_S_DRIVES:
  871                         /*
  872                          * this esm sensor represents 4 kernel sensors, so we
  873                          * go through these hoops to deal with it.
  874                          */
  875                         nsensors = 4;
  876                         s = malloc(sizeof(struct ksensor) * nsensors, M_DEVBUF,
  877                             M_NOWAIT);
  878                         if (s == NULL) {
  879                                 free(es, M_DEVBUF);
  880                                 return;
  881                         }
  882                         memset(s, 0, sizeof(struct ksensor) * nsensors);
  883 
  884                         for (j = 0; j < nsensors; j++) {
  885                                 snprintf(s[j].desc, sizeof(s[j].desc), "%s %d",
  886                                     sensor_map[i].name, sensor_map[i].arg + j);
  887                         }
  888                         break;
  889                 case ESM_S_PWRSUP:
  890                         /*
  891                          * the esm pwrsup sensor has a bitfield for its value,
  892                          * this expands it out to 6 separate indicators
  893                          */
  894                         nsensors = 6;
  895                         s = malloc(sizeof(struct ksensor) * nsensors, M_DEVBUF,
  896                             M_NOWAIT);
  897                         if (s == NULL) {
  898                                 free(es, M_DEVBUF);
  899                                 return;
  900                         }
  901                         memset(s, 0, sizeof(struct ksensor) * nsensors);
  902 
  903                         for (j = 0; j < nsensors; j++) {
  904                                 snprintf(s[j].desc, sizeof(s[j].desc), "%s %s",
  905                                     sensor_map[i].name, psulabels[j]);
  906                         }
  907                         break;
  908 
  909                 case ESM_S_TEMP:
  910                 case ESM_S_FANRPM:
  911                 case ESM_S_AMPS:
  912                 case ESM_S_VOLTS:
  913                 case ESM_S_VOLTSx10:
  914                         if (esm_thresholds(sc, devmap, es) != 0) {
  915                                 free(es, M_DEVBUF);
  916                                 continue;
  917                         }
  918                         /* FALLTHROUGH */
  919 
  920                 default:
  921                         nsensors = 1;
  922                         s = malloc(sizeof(struct ksensor), M_DEVBUF, M_NOWAIT);
  923                         if (s == NULL) {
  924                                 free(es, M_DEVBUF);
  925                                 return;
  926                         }
  927                         memset(s, 0, sizeof(struct ksensor));
  928 
  929                         strlcpy(s->desc, sensor_map[i].name, sizeof(s->desc));
  930                         break;
  931                 }
  932 
  933                 for (j = 0; j < nsensors; j++) {
  934                         s[j].type = esm_typemap[es->es_type];
  935                         sensor_attach(&sc->sc_sensordev, &s[j]);
  936                 }
  937 
  938                 es->es_sensor = s;
  939                 TAILQ_INSERT_TAIL(&sc->sc_sensors, es, es_entry);
  940         }
  941 }
  942 
  943 int
  944 esm_thresholds(struct esm_softc *sc, struct esm_devmap *devmap,
  945     struct esm_sensor *es)
  946 {
  947         struct esm_smb_req      req;
  948         struct esm_smb_resp     resp;
  949         struct esm_smb_resp_thr *thr = &resp.resp_thr;
  950 
  951         memset(&req, 0, sizeof(req));
  952         req.h_cmd = ESM2_CMD_SMB_XMIT_RECV;
  953         req.h_dev = devmap->index;
  954         req.h_txlen = sizeof(req.req_thr);
  955         req.h_rxlen = sizeof(resp.resp_thr);
  956 
  957         req.req_thr.t_cmd = ESM2_SMB_SENSOR_THRESHOLDS;
  958         req.req_thr.t_sensor = es->es_id;
  959 
  960         if (esm_smb_cmd(sc, &req, &resp, 1, 0) != 0)
  961                 return (1);
  962 
  963         DPRINTFN(2, "%s: dev: %d sensor: %d lo fail: %d hi fail: %d "
  964             "lo warn: %d hi warn: %d hysterisis: %d checksum: 0x%02x\n",
  965             DEVNAME(sc), devmap->index, es->es_id, thr->t_lo_fail,
  966             thr->t_hi_fail, thr->t_lo_warn, thr->t_hi_warn, thr->t_hysterisis,
  967             thr->t_checksum);
  968 
  969         es->es_thresholds.th_lo_crit = thr->t_lo_fail;
  970         es->es_thresholds.th_lo_warn = thr->t_lo_warn;
  971         es->es_thresholds.th_hi_warn = thr->t_hi_warn;
  972         es->es_thresholds.th_hi_crit = thr->t_hi_fail;
  973 
  974         return (0);
  975 }
  976 
  977 int
  978 esm_bmc_ready(struct esm_softc *sc, int port, u_int8_t mask, u_int8_t val,
  979     int wait)
  980 {
  981         unsigned int            count = wait ? 0 : 0xfffff;
  982 
  983         do {
  984                 if ((EREAD(sc, port) & mask) == val)
  985                         return (0);
  986         } while (count++ < 0xfffff);
  987 
  988         return (1);
  989 }
  990 
  991 int
  992 esm_cmd(struct esm_softc *sc, void *cmd, size_t cmdlen, void *resp,
  993     size_t resplen, int wait, int step)
  994 {
  995         u_int8_t                *tx = (u_int8_t *)cmd;
  996         u_int8_t                *rx = (u_int8_t *)resp;
  997         int                     i;
  998 
  999         switch (step) {
 1000         case 0:
 1001         case 1:
 1002                 /* Wait for card ready */
 1003                 if (esm_bmc_ready(sc, ESM2_CTRL_REG, ESM2_TC_READY,
 1004                     0, wait) != 0)
 1005                         return (1); /* busy */
 1006 
 1007                 /* Write command data to port */
 1008                 ECTRLWR(sc, ESM2_TC_CLR_WPTR);
 1009                 for (i = 0; i < cmdlen; i++) {
 1010                         DPRINTFN(2, "write: %.2x\n", *tx);
 1011                         EDATAWR(sc, *tx);
 1012                         tx++;
 1013                 }
 1014 
 1015                 /* Ring doorbell... */
 1016                 ECTRLWR(sc, ESM2_TC_H2ECDB);
 1017                 /* FALLTHROUGH */
 1018         case 2:
 1019                 /* ...and wait */
 1020                 if (esm_bmc_ready(sc, ESM2_CTRL_REG, ESM2_TC_EC2HDB,
 1021                     ESM2_TC_EC2HDB, wait) != 0)
 1022                         return (2);
 1023 
 1024                 /* Set host busy semaphore and clear doorbell */
 1025                 ECTRLWR(sc, ESM2_TC_HOSTBUSY);
 1026                 ECTRLWR(sc, ESM2_TC_EC2HDB);
 1027         
 1028                 /* Read response data from port */
 1029                 ECTRLWR(sc, ESM2_TC_CLR_RPTR);
 1030                 for (i = 0; i < resplen; i++) {
 1031                         *rx = EDATARD(sc);
 1032                         DPRINTFN(2, "read = %.2x\n", *rx);
 1033                         rx++;
 1034                 }
 1035 
 1036                 /* release semaphore */
 1037                 ECTRLWR(sc, ESM2_TC_HOSTBUSY);
 1038                 break;
 1039         }
 1040 
 1041         return (0);
 1042 }
 1043 
 1044 int
 1045 esm_smb_cmd(struct esm_softc *sc, struct esm_smb_req *req,
 1046     struct esm_smb_resp *resp, int wait, int step)
 1047 {
 1048         int                     err;
 1049 
 1050         memset(resp, 0, sizeof(struct esm_smb_resp));
 1051 
 1052         err = esm_cmd(sc, req, sizeof(req->hdr) + req->h_txlen, resp,
 1053             sizeof(resp->hdr) + req->h_rxlen, wait, step);
 1054         if (err)
 1055                 return (err);
 1056 
 1057         if (resp->h_status != 0 || resp->h_i2csts != 0) {
 1058                 DPRINTFN(3, "%s: dev: 0x%02x error status: 0x%02x "
 1059                     "i2csts: 0x%02x procsts: 0x%02x tx: 0x%02x rx: 0x%02x\n",
 1060                     __func__, req->h_dev, resp->h_status, resp->h_i2csts,
 1061                     resp->h_procsts, resp->h_rx, resp->h_tx);
 1062                 return (1);
 1063         }
 1064 
 1065         return (0);
 1066 }
 1067 
 1068 int64_t
 1069 esm_val2temp(u_int16_t value)
 1070 {
 1071         return (((int64_t)value * 100000) + 273150000);
 1072 }
 1073 
 1074 int64_t
 1075 esm_val2volts(u_int16_t value)
 1076 {
 1077         return ((int64_t)value * 1000);
 1078 }
 1079 
 1080 int64_t
 1081 esm_val2amps(u_int16_t value)
 1082 {
 1083         return ((int64_t)value * 100000);
 1084 }

/* [<][>][^][v][top][bottom][index][help] */