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