xref: /openbsd-src/sys/arch/i386/i386/esm.c (revision f4e7063748a2ac72b2bab4389c0a7efc72d82189)
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