xref: /openbsd/sys/arch/sparc64/dev/lom.c (revision df54a7c0)
1*df54a7c0Skettenis /*	$OpenBSD: lom.c,v 1.14 2009/09/27 17:59:55 kettenis Exp $	*/
22613757eSkettenis /*
35f2dcfb1Skettenis  * Copyright (c) 2009 Mark Kettenis
42613757eSkettenis  *
52613757eSkettenis  * Permission to use, copy, modify, and distribute this software for any
62613757eSkettenis  * purpose with or without fee is hereby granted, provided that the above
72613757eSkettenis  * copyright notice and this permission notice appear in all copies.
82613757eSkettenis  *
92613757eSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102613757eSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112613757eSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122613757eSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132613757eSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142613757eSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152613757eSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162613757eSkettenis  */
172613757eSkettenis 
182613757eSkettenis #include <sys/param.h>
192613757eSkettenis #include <sys/device.h>
206801a748Skettenis #include <sys/kernel.h>
21fc69c4e1Skettenis #include <sys/proc.h>
222613757eSkettenis #include <sys/sensors.h>
232613757eSkettenis #include <sys/systm.h>
24877407b4Skettenis #include <sys/timeout.h>
252613757eSkettenis 
262613757eSkettenis #include <machine/autoconf.h>
272613757eSkettenis #include <machine/openfirm.h>
282613757eSkettenis 
292613757eSkettenis #include <sparc64/dev/ebusreg.h>
302613757eSkettenis #include <sparc64/dev/ebusvar.h>
312613757eSkettenis 
322613757eSkettenis /*
3313d051d6Skettenis  * LOMlite is a so far unidentified microcontroller.
3413d051d6Skettenis  */
3513d051d6Skettenis #define LOM1_STATUS		0x00	/* R */
3613d051d6Skettenis #define  LOM1_STATUS_BUSY	0x80
3713d051d6Skettenis #define LOM1_CMD		0x00	/* W */
3813d051d6Skettenis #define LOM1_DATA		0x01	/* R/W */
3913d051d6Skettenis 
4013d051d6Skettenis /*
4113d051d6Skettenis  * LOMlite2 is implemented as a H8/3437 microcontroller which has its
422613757eSkettenis  * on-chip host interface hooked up to EBus.
432613757eSkettenis  */
4413d051d6Skettenis #define LOM2_DATA		0x00	/* R/W */
4513d051d6Skettenis #define LOM2_CMD		0x01	/* W */
4613d051d6Skettenis #define LOM2_STATUS		0x01	/* R */
4713d051d6Skettenis #define  LOM2_STATUS_OBF	0x01	/* Output Buffer Full */
4813d051d6Skettenis #define  LOM2_STATUS_IBF	0x02	/* Input Buffer Full  */
492613757eSkettenis 
505f2dcfb1Skettenis #define LOM_IDX_CMD		0x00
515f2dcfb1Skettenis #define  LOM_IDX_CMD_GENERIC	0x00
525f2dcfb1Skettenis #define  LOM_IDX_CMD_TEMP	0x04
5302222f5cSkettenis #define  LOM_IDX_CMD_FAN	0x05
545f2dcfb1Skettenis 
552613757eSkettenis #define LOM_IDX_FW_REV		0x01	/* Firmware revision  */
562613757eSkettenis 
5702222f5cSkettenis #define LOM_IDX_FAN1		0x04	/* Fan speed */
5802222f5cSkettenis #define LOM_IDX_FAN2		0x05
5902222f5cSkettenis #define LOM_IDX_FAN3		0x06
6002222f5cSkettenis #define LOM_IDX_FAN4		0x07
6178eeb547Skettenis #define LOM_IDX_PSU1		0x08	/* PSU status */
6278eeb547Skettenis #define LOM_IDX_PSU2		0x09
6378eeb547Skettenis #define LOM_IDX_PSU3		0x0a
6478eeb547Skettenis #define  LOM_PSU_INPUTA		0x01
6578eeb547Skettenis #define  LOM_PSU_INPUTB		0x02
6678eeb547Skettenis #define  LOM_PSU_OUTPUT		0x04
6778eeb547Skettenis #define  LOM_PSU_PRESENT	0x08
6878eeb547Skettenis #define  LOM_PSU_STANDBY	0x10
6902222f5cSkettenis 
702613757eSkettenis #define LOM_IDX_TEMP1		0x18	/* Temperature */
7102222f5cSkettenis #define LOM_IDX_TEMP2		0x19
7202222f5cSkettenis #define LOM_IDX_TEMP3		0x1a
7302222f5cSkettenis #define LOM_IDX_TEMP4		0x1b
7402222f5cSkettenis #define LOM_IDX_TEMP5		0x1c
7502222f5cSkettenis #define LOM_IDX_TEMP6		0x1d
7602222f5cSkettenis #define LOM_IDX_TEMP7		0x1e
7702222f5cSkettenis #define LOM_IDX_TEMP8		0x1f
782613757eSkettenis 
795f2dcfb1Skettenis #define LOM_IDX_LED1		0x25
805f2dcfb1Skettenis 
815f2dcfb1Skettenis #define LOM_IDX_ALARM		0x30
82877407b4Skettenis #define LOM_IDX_WDOG_CTL	0x31
83877407b4Skettenis #define  LOM_WDOG_ENABLE	0x01
84877407b4Skettenis #define  LOM_WDOG_RESET		0x02
85877407b4Skettenis #define  LOM_WDOG_AL3_WDOG	0x04
86877407b4Skettenis #define  LOM_WDOG_AL3_FANPSU	0x08
87877407b4Skettenis #define LOM_IDX_WDOG_TIME	0x32
8813d051d6Skettenis #define  LOM_WDOG_TIME_MAX	126
895f2dcfb1Skettenis 
9013d051d6Skettenis #define LOM1_IDX_HOSTNAME1	0x33
9113d051d6Skettenis #define LOM1_IDX_HOSTNAME2	0x34
9213d051d6Skettenis #define LOM1_IDX_HOSTNAME3	0x35
9313d051d6Skettenis #define LOM1_IDX_HOSTNAME4	0x36
9413d051d6Skettenis #define LOM1_IDX_HOSTNAME5	0x37
9513d051d6Skettenis #define LOM1_IDX_HOSTNAME6	0x38
9613d051d6Skettenis #define LOM1_IDX_HOSTNAME7	0x39
9713d051d6Skettenis #define LOM1_IDX_HOSTNAME8	0x3a
9813d051d6Skettenis #define LOM1_IDX_HOSTNAME9	0x3b
9913d051d6Skettenis #define LOM1_IDX_HOSTNAME10	0x3c
10013d051d6Skettenis #define LOM1_IDX_HOSTNAME11	0x3d
10113d051d6Skettenis #define LOM1_IDX_HOSTNAME12	0x3e
10213d051d6Skettenis 
10313d051d6Skettenis #define LOM2_IDX_HOSTNAMELEN	0x38
10413d051d6Skettenis #define LOM2_IDX_HOSTNAME	0x39
1056801a748Skettenis 
10602222f5cSkettenis #define LOM_IDX_CONFIG		0x5d
10702222f5cSkettenis #define LOM_IDX_FAN1_CAL	0x5e
10802222f5cSkettenis #define LOM_IDX_FAN2_CAL	0x5f
10902222f5cSkettenis #define LOM_IDX_FAN3_CAL	0x60
11002222f5cSkettenis #define LOM_IDX_FAN4_CAL	0x61
11102222f5cSkettenis #define LOM_IDX_FAN1_LOW	0x62
11202222f5cSkettenis #define LOM_IDX_FAN2_LOW	0x63
11302222f5cSkettenis #define LOM_IDX_FAN3_LOW	0x64
11402222f5cSkettenis #define LOM_IDX_FAN4_LOW	0x65
11502222f5cSkettenis 
11602222f5cSkettenis #define LOM_IDX_CONFIG2		0x66
11702222f5cSkettenis #define LOM_IDX_CONFIG3		0x67
11802222f5cSkettenis 
1192613757eSkettenis #define LOM_IDX_PROBE55		0x7e	/* Always returns 0x55 */
1202613757eSkettenis #define LOM_IDX_PROBEAA		0x7f	/* Always returns 0xaa */
1212613757eSkettenis 
1225e80de5eSkettenis #define LOM_IDX_WRITE		0x80
1235e80de5eSkettenis 
1245f2dcfb1Skettenis #define LOM_IDX4_TEMP_NAME_START	0x40
1255f2dcfb1Skettenis #define LOM_IDX4_TEMP_NAME_END		0xff
1265f2dcfb1Skettenis 
12702222f5cSkettenis #define LOM_IDX5_FAN_NAME_START		0x40
12802222f5cSkettenis #define LOM_IDX5_FAN_NAME_END		0xff
12902222f5cSkettenis 
13002222f5cSkettenis #define LOM_MAX_FAN	4
13102222f5cSkettenis #define LOM_MAX_PSU	3
13202222f5cSkettenis #define LOM_MAX_TEMP	8
13302222f5cSkettenis 
1345e80de5eSkettenis struct lom_cmd {
1355e80de5eSkettenis 	uint8_t			lc_cmd;
1365e80de5eSkettenis 	uint8_t			lc_data;
1375e80de5eSkettenis 
1385e80de5eSkettenis 	TAILQ_ENTRY(lom_cmd)	lc_next;
1395e80de5eSkettenis };
1405e80de5eSkettenis 
1412613757eSkettenis struct lom_softc {
1422613757eSkettenis 	struct device		sc_dev;
1432613757eSkettenis 	bus_space_tag_t		sc_iot;
1442613757eSkettenis 	bus_space_handle_t	sc_ioh;
1452613757eSkettenis 
14613d051d6Skettenis 	int			sc_type;
14713d051d6Skettenis #define LOM_LOMLITE		0
14813d051d6Skettenis #define LOM_LOMLITE2		2
1495f2dcfb1Skettenis 	int			sc_space;
1505f2dcfb1Skettenis 
15102222f5cSkettenis 	struct ksensor		sc_fan[LOM_MAX_FAN];
15278eeb547Skettenis 	struct ksensor		sc_psu[LOM_MAX_PSU];
15302222f5cSkettenis 	struct ksensor		sc_temp[LOM_MAX_TEMP];
1542613757eSkettenis 	struct ksensordev	sc_sensordev;
15502222f5cSkettenis 
15602222f5cSkettenis 	int			sc_num_fan;
15702222f5cSkettenis 	int			sc_num_psu;
15802222f5cSkettenis 	int			sc_num_temp;
15902222f5cSkettenis 
16002222f5cSkettenis 	uint8_t			sc_fan_cal[LOM_MAX_FAN];
16102222f5cSkettenis 	uint8_t			sc_fan_low[LOM_MAX_FAN];
1626801a748Skettenis 
1636801a748Skettenis 	char			sc_hostname[MAXHOSTNAMELEN];
164877407b4Skettenis 
165877407b4Skettenis 	struct timeout		sc_wdog_to;
166877407b4Skettenis 	int			sc_wdog_period;
1675223c73eSkettenis 	uint8_t			sc_wdog_ctl;
1685e80de5eSkettenis 	struct lom_cmd		sc_wdog_pat;
169fc69c4e1Skettenis 
1705e80de5eSkettenis 	TAILQ_HEAD(, lom_cmd)	sc_queue;
1715e80de5eSkettenis 	struct mutex		sc_queue_mtx;
172fc69c4e1Skettenis 	struct timeout		sc_state_to;
173fc69c4e1Skettenis 	int			sc_state;
174fc69c4e1Skettenis #define LOM_STATE_IDLE		0
1755e80de5eSkettenis #define LOM_STATE_CMD		1
1765e80de5eSkettenis #define LOM_STATE_DATA		2
1775e80de5eSkettenis 	int			sc_retry;
1782613757eSkettenis };
1792613757eSkettenis 
1802613757eSkettenis int	lom_match(struct device *, void *, void *);
1812613757eSkettenis void	lom_attach(struct device *, struct device *, void *);
1822613757eSkettenis 
1832613757eSkettenis struct cfattach lom_ca = {
1842613757eSkettenis 	sizeof(struct lom_softc), lom_match, lom_attach
1852613757eSkettenis };
1862613757eSkettenis 
1872613757eSkettenis struct cfdriver lom_cd = {
1882613757eSkettenis 	NULL, "lom", DV_DULL
1892613757eSkettenis };
1902613757eSkettenis 
1912613757eSkettenis int	lom_read(struct lom_softc *, uint8_t, uint8_t *);
1922613757eSkettenis int	lom_write(struct lom_softc *, uint8_t, uint8_t);
1935e80de5eSkettenis void	lom_queue_cmd(struct lom_softc *, struct lom_cmd *);
19413d051d6Skettenis int	lom1_read(struct lom_softc *, uint8_t, uint8_t *);
19513d051d6Skettenis int	lom1_write(struct lom_softc *, uint8_t, uint8_t);
1965e80de5eSkettenis int	lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *);
1975e80de5eSkettenis int	lom1_write_polled(struct lom_softc *, uint8_t, uint8_t);
1985e80de5eSkettenis void	lom1_queue_cmd(struct lom_softc *, struct lom_cmd *);
1995e80de5eSkettenis void	lom1_dequeue_cmd(struct lom_softc *, struct lom_cmd *);
2005e80de5eSkettenis void	lom1_process_queue(void *);
2015e80de5eSkettenis void	lom1_process_queue_locked(struct lom_softc *);
20213d051d6Skettenis int	lom2_read(struct lom_softc *, uint8_t, uint8_t *);
20313d051d6Skettenis int	lom2_write(struct lom_softc *, uint8_t, uint8_t);
2045e80de5eSkettenis void	lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);
2052613757eSkettenis 
2065f2dcfb1Skettenis int	lom_init_desc(struct lom_softc *sc);
2072613757eSkettenis void	lom_refresh(void *);
20813d051d6Skettenis void	lom1_write_hostname(struct lom_softc *);
20913d051d6Skettenis void	lom2_write_hostname(struct lom_softc *);
2102613757eSkettenis 
211877407b4Skettenis void	lom_wdog_pat(void *);
212877407b4Skettenis int	lom_wdog_cb(void *, int);
213877407b4Skettenis 
2142613757eSkettenis int
2152613757eSkettenis lom_match(struct device *parent, void *match, void *aux)
2162613757eSkettenis {
2172613757eSkettenis 	struct ebus_attach_args *ea = aux;
2182613757eSkettenis 
219fc69c4e1Skettenis 	if (strcmp(ea->ea_name, "SUNW,lom") == 0 ||
220fc69c4e1Skettenis 	    strcmp(ea->ea_name, "SUNW,lomh") == 0)
2212613757eSkettenis 		return (1);
2222613757eSkettenis 
2232613757eSkettenis 	return (0);
2242613757eSkettenis }
2252613757eSkettenis 
2262613757eSkettenis void
2272613757eSkettenis lom_attach(struct device *parent, struct device *self, void *aux)
2282613757eSkettenis {
2292613757eSkettenis 	struct lom_softc *sc = (void *)self;
2302613757eSkettenis 	struct ebus_attach_args *ea = aux;
23102222f5cSkettenis 	uint8_t reg, fw_rev, config, config2, config3;
23213d051d6Skettenis 	uint8_t cal, low;
23302222f5cSkettenis 	int i;
2342613757eSkettenis 
23513d051d6Skettenis 	if (strcmp(ea->ea_name, "SUNW,lomh") == 0)
23613d051d6Skettenis 		sc->sc_type = LOM_LOMLITE2;
23713d051d6Skettenis 
238d151cb6cSkettenis 	if (ebus_bus_map(ea->ea_iotag, 0,
2392613757eSkettenis 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
240d151cb6cSkettenis 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
241d151cb6cSkettenis 		sc->sc_iot = ea->ea_iotag;
242d151cb6cSkettenis 	} else if (ebus_bus_map(ea->ea_memtag, 0,
243d151cb6cSkettenis 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
244d151cb6cSkettenis 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
245d151cb6cSkettenis 		sc->sc_iot = ea->ea_memtag;
246d151cb6cSkettenis 	} else {
2472613757eSkettenis 		printf(": can't map register space\n");
2482613757eSkettenis                 return;
2492613757eSkettenis 	}
2502613757eSkettenis 
25113d051d6Skettenis 	if (sc->sc_type < LOM_LOMLITE2) {
25213d051d6Skettenis 		/* XXX Magic */
25313d051d6Skettenis 		bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
25413d051d6Skettenis 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca);
255fc69c4e1Skettenis 
2565e80de5eSkettenis 		TAILQ_INIT(&sc->sc_queue);
2575e80de5eSkettenis 		mtx_init(&sc->sc_queue_mtx, IPL_BIO);
2585e80de5eSkettenis 		timeout_set(&sc->sc_state_to, lom1_process_queue, sc);
25913d051d6Skettenis 	}
26013d051d6Skettenis 
2612613757eSkettenis 	if (lom_read(sc, LOM_IDX_PROBE55, &reg) || reg != 0x55 ||
2622613757eSkettenis 	    lom_read(sc, LOM_IDX_PROBEAA, &reg) || reg != 0xaa ||
26302222f5cSkettenis 	    lom_read(sc, LOM_IDX_FW_REV, &fw_rev) ||
26413d051d6Skettenis 	    lom_read(sc, LOM_IDX_CONFIG, &config))
26502222f5cSkettenis 	{
2662613757eSkettenis 		printf(": not responding\n");
2672613757eSkettenis 		return;
2682613757eSkettenis 	}
2692613757eSkettenis 
27013d051d6Skettenis 	config2 = config3 = 0;
27113d051d6Skettenis 	if (sc->sc_type >= LOM_LOMLITE2) {
27213d051d6Skettenis 		lom_read(sc, LOM_IDX_CONFIG2, &config2);
27313d051d6Skettenis 		lom_read(sc, LOM_IDX_CONFIG3, &config3);
27413d051d6Skettenis 	}
27513d051d6Skettenis 
27602222f5cSkettenis 	sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN);
27702222f5cSkettenis 	sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU);
27802222f5cSkettenis 	sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP);
27902222f5cSkettenis 
28002222f5cSkettenis 	for (i = 0; i < sc->sc_num_fan; i++) {
28102222f5cSkettenis 		if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) ||
28202222f5cSkettenis 		    lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) {
28302222f5cSkettenis 			printf(": can't read fan information\n");
28402222f5cSkettenis 			return;
28502222f5cSkettenis 		}
28602222f5cSkettenis 		sc->sc_fan_cal[i] = cal;
28702222f5cSkettenis 		sc->sc_fan_low[i] = low;
28802222f5cSkettenis 	}
28902222f5cSkettenis 
2902613757eSkettenis 	/* Initialize sensor data. */
2912613757eSkettenis 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
2922613757eSkettenis 	    sizeof(sc->sc_sensordev.xname));
29302222f5cSkettenis 	for (i = 0; i < sc->sc_num_fan; i++) {
29402222f5cSkettenis 		sc->sc_fan[i].type = SENSOR_FANRPM;
29502222f5cSkettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_fan[i]);
29613d051d6Skettenis 		snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc),
29713d051d6Skettenis 		    "fan%d", i + 1);
29802222f5cSkettenis 	}
29978eeb547Skettenis 	for (i = 0; i < sc->sc_num_psu; i++) {
30078eeb547Skettenis 		sc->sc_psu[i].type = SENSOR_INDICATOR;
30178eeb547Skettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_psu[i]);
30278eeb547Skettenis 		snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc),
30378eeb547Skettenis 		    "PSU%d", i + 1);
30478eeb547Skettenis 	}
30502222f5cSkettenis 	for (i = 0; i < sc->sc_num_temp; i++) {
30602222f5cSkettenis 		sc->sc_temp[i].type = SENSOR_TEMP;
30702222f5cSkettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_temp[i]);
30802222f5cSkettenis 	}
3095f2dcfb1Skettenis 	if (lom_init_desc(sc)) {
3105f2dcfb1Skettenis 		printf(": can't read sensor names\n");
3115f2dcfb1Skettenis 		return;
3125f2dcfb1Skettenis 	}
3132613757eSkettenis 
3142613757eSkettenis 	if (sensor_task_register(sc, lom_refresh, 5) == NULL) {
3152613757eSkettenis 		printf(": unable to register update task\n");
3162613757eSkettenis 		return;
3172613757eSkettenis 	}
3182613757eSkettenis 
3192613757eSkettenis 	sensordev_install(&sc->sc_sensordev);
3202613757eSkettenis 
321877407b4Skettenis 	/*
322877407b4Skettenis 	 * We configure the watchdog to turn on the fault LED when the
323877407b4Skettenis 	 * watchdog timer expires.  We run our own timeout to pat it
324877407b4Skettenis 	 * such that this won't happen unless the kernel hangs.  When
325877407b4Skettenis 	 * the watchdog is explicitly configured using sysctl(8), we
326877407b4Skettenis 	 * reconfigure it to reset the machine and let the standard
327877407b4Skettenis 	 * watchdog(4) machinery take over.
328877407b4Skettenis 	 */
329877407b4Skettenis 	lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
3305223c73eSkettenis 	lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl);
3315223c73eSkettenis 	sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
3325223c73eSkettenis 	sc->sc_wdog_ctl |= LOM_WDOG_ENABLE;
3335223c73eSkettenis 	lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
334877407b4Skettenis 	timeout_set(&sc->sc_wdog_to, lom_wdog_pat, sc);
335877407b4Skettenis 	timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
336877407b4Skettenis 
337877407b4Skettenis 	wdog_register(sc, lom_wdog_cb);
338877407b4Skettenis 
3392613757eSkettenis 	printf(": rev %d.%d\n", fw_rev >> 4, fw_rev & 0x0f);
3402613757eSkettenis }
3412613757eSkettenis 
3422613757eSkettenis int
3432613757eSkettenis lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
3442613757eSkettenis {
34513d051d6Skettenis 	if (sc->sc_type < LOM_LOMLITE2)
34613d051d6Skettenis 		return lom1_read(sc, reg, val);
34713d051d6Skettenis 	else
34813d051d6Skettenis 		return lom2_read(sc, reg, val);
3492613757eSkettenis }
3502613757eSkettenis 
3515f2dcfb1Skettenis int
3525f2dcfb1Skettenis lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
3535f2dcfb1Skettenis {
35413d051d6Skettenis 	if (sc->sc_type < LOM_LOMLITE2)
35513d051d6Skettenis 		return lom1_write(sc, reg, val);
35613d051d6Skettenis 	else
35713d051d6Skettenis 		return lom2_write(sc, reg, val);
35813d051d6Skettenis }
35913d051d6Skettenis 
3605e80de5eSkettenis void
3615e80de5eSkettenis lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
3625e80de5eSkettenis {
3635e80de5eSkettenis 	if (sc->sc_type < LOM_LOMLITE2)
3645e80de5eSkettenis 		return lom1_queue_cmd(sc, lc);
3655e80de5eSkettenis 	else
3665e80de5eSkettenis 		return lom2_queue_cmd(sc, lc);
3675e80de5eSkettenis }
3685e80de5eSkettenis 
36913d051d6Skettenis int
37013d051d6Skettenis lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
37113d051d6Skettenis {
3725e80de5eSkettenis 	struct lom_cmd lc;
373fc69c4e1Skettenis 	int error;
374fc69c4e1Skettenis 
375fc69c4e1Skettenis 	if (cold)
376fc69c4e1Skettenis 		return lom1_read_polled(sc, reg, val);
377fc69c4e1Skettenis 
3785e80de5eSkettenis 	lc.lc_cmd = reg;
3795e80de5eSkettenis 	lc.lc_data = 0xff;
3805e80de5eSkettenis 	lom1_queue_cmd(sc, &lc);
381fc69c4e1Skettenis 
3825e80de5eSkettenis 	error = tsleep(&lc, PZERO, "lomrd", hz);
3835e80de5eSkettenis 	if (error)
3845e80de5eSkettenis 		lom1_dequeue_cmd(sc, &lc);
385fc69c4e1Skettenis 
3865e80de5eSkettenis 	*val = lc.lc_data;
3875e80de5eSkettenis 
3885e80de5eSkettenis 	return (error);
3895e80de5eSkettenis }
3905e80de5eSkettenis 
3915e80de5eSkettenis int
3925e80de5eSkettenis lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
3935e80de5eSkettenis {
3945e80de5eSkettenis 	struct lom_cmd lc;
3955e80de5eSkettenis 	int error;
3965e80de5eSkettenis 
3975e80de5eSkettenis 	if (cold)
3985e80de5eSkettenis 		return lom1_write_polled(sc, reg, val);
3995e80de5eSkettenis 
4005e80de5eSkettenis 	lc.lc_cmd = reg | LOM_IDX_WRITE;
4015e80de5eSkettenis 	lc.lc_data = val;
4025e80de5eSkettenis 	lom1_queue_cmd(sc, &lc);
4035e80de5eSkettenis 
4045e80de5eSkettenis 	error = tsleep(&lc, PZERO, "lomwr", hz);
4055e80de5eSkettenis 	if (error)
4065e80de5eSkettenis 		lom1_dequeue_cmd(sc, &lc);
407fc69c4e1Skettenis 
408fc69c4e1Skettenis 	return (error);
409fc69c4e1Skettenis }
410fc69c4e1Skettenis 
411fc69c4e1Skettenis int
412fc69c4e1Skettenis lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
413fc69c4e1Skettenis {
41413d051d6Skettenis 	uint8_t str;
41513d051d6Skettenis 	int i;
41613d051d6Skettenis 
41713d051d6Skettenis 	/* Wait for input buffer to become available. */
4183c40421dSkettenis 	for (i = 30; i > 0; i--) {
41913d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4203c40421dSkettenis 		delay(1000);
42113d051d6Skettenis 		if ((str & LOM1_STATUS_BUSY) == 0)
42213d051d6Skettenis 			break;
42313d051d6Skettenis 	}
42413d051d6Skettenis 	if (i == 0)
42513d051d6Skettenis 		return (ETIMEDOUT);
42613d051d6Skettenis 
42713d051d6Skettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
42813d051d6Skettenis 
42913d051d6Skettenis 	/* Wait until the microcontroller fills output buffer. */
4303c40421dSkettenis 	for (i = 30; i > 0; i--) {
43113d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4323c40421dSkettenis 		delay(1000);
43313d051d6Skettenis 		if ((str & LOM1_STATUS_BUSY) == 0)
43413d051d6Skettenis 			break;
43513d051d6Skettenis 	}
43613d051d6Skettenis 	if (i == 0)
43713d051d6Skettenis 		return (ETIMEDOUT);
43813d051d6Skettenis 
43913d051d6Skettenis 	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
44013d051d6Skettenis 	return (0);
44113d051d6Skettenis }
44213d051d6Skettenis 
44313d051d6Skettenis int
4445e80de5eSkettenis lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
44513d051d6Skettenis {
44613d051d6Skettenis 	uint8_t str;
44713d051d6Skettenis 	int i;
44813d051d6Skettenis 
44913d051d6Skettenis 	/* Wait for input buffer to become available. */
4503c40421dSkettenis 	for (i = 30; i > 0; i--) {
45113d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4523c40421dSkettenis 		delay(1000);
45313d051d6Skettenis 		if ((str & LOM1_STATUS_BUSY) == 0)
45413d051d6Skettenis 			break;
45513d051d6Skettenis 	}
45613d051d6Skettenis 	if (i == 0)
45713d051d6Skettenis 		return (ETIMEDOUT);
45813d051d6Skettenis 
4595e80de5eSkettenis 	reg |= LOM_IDX_WRITE;
4605e80de5eSkettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
46113d051d6Skettenis 
46213d051d6Skettenis 	/* Wait until the microcontroller fills output buffer. */
4633c40421dSkettenis 	for (i = 30; i > 0; i--) {
46413d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
4653c40421dSkettenis 		delay(1000);
46613d051d6Skettenis 		if ((str & LOM1_STATUS_BUSY) == 0)
46713d051d6Skettenis 			break;
46813d051d6Skettenis 	}
46913d051d6Skettenis 	if (i == 0)
47013d051d6Skettenis 		return (ETIMEDOUT);
47113d051d6Skettenis 
47213d051d6Skettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val);
47313d051d6Skettenis 
47413d051d6Skettenis 	return (0);
47513d051d6Skettenis }
47613d051d6Skettenis 
477fc69c4e1Skettenis void
4785e80de5eSkettenis lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
4795e80de5eSkettenis {
4805e80de5eSkettenis 	mtx_enter(&sc->sc_queue_mtx);
4815e80de5eSkettenis 	TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
4825e80de5eSkettenis 	if (sc->sc_state == LOM_STATE_IDLE) {
4835e80de5eSkettenis 		sc->sc_state = LOM_STATE_CMD;
4845e80de5eSkettenis 		lom1_process_queue_locked(sc);
4855e80de5eSkettenis 	}
4865e80de5eSkettenis 	mtx_leave(&sc->sc_queue_mtx);
4875e80de5eSkettenis }
4885e80de5eSkettenis 
4895e80de5eSkettenis void
4905e80de5eSkettenis lom1_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
4915e80de5eSkettenis {
4925e80de5eSkettenis 	struct lom_cmd *lcp;
4935e80de5eSkettenis 
4945e80de5eSkettenis 	mtx_enter(&sc->sc_queue_mtx);
4955e80de5eSkettenis 	TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) {
4965e80de5eSkettenis 		if (lcp == lc) {
4975e80de5eSkettenis 			TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
4985e80de5eSkettenis 			break;
4995e80de5eSkettenis 		}
5005e80de5eSkettenis 	}
5015e80de5eSkettenis 	mtx_leave(&sc->sc_queue_mtx);
5025e80de5eSkettenis }
5035e80de5eSkettenis 
5045e80de5eSkettenis void
5055e80de5eSkettenis lom1_process_queue(void *arg)
506fc69c4e1Skettenis {
507fc69c4e1Skettenis 	struct lom_softc *sc = arg;
5085e80de5eSkettenis 
5095e80de5eSkettenis 	mtx_enter(&sc->sc_queue_mtx);
5105e80de5eSkettenis 	lom1_process_queue_locked(sc);
5115e80de5eSkettenis 	mtx_leave(&sc->sc_queue_mtx);
5125e80de5eSkettenis }
5135e80de5eSkettenis 
5145e80de5eSkettenis void
5155e80de5eSkettenis lom1_process_queue_locked(struct lom_softc *sc)
5165e80de5eSkettenis {
5175e80de5eSkettenis 	struct lom_cmd *lc;
518fc69c4e1Skettenis 	uint8_t str;
519fc69c4e1Skettenis 
5205e80de5eSkettenis 	lc = TAILQ_FIRST(&sc->sc_queue);
5215e80de5eSkettenis 	KASSERT(lc != NULL);
5225e80de5eSkettenis 
523fc69c4e1Skettenis 	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
524fc69c4e1Skettenis 	if (str & LOM1_STATUS_BUSY) {
5255e80de5eSkettenis 		if (sc->sc_retry++ > 30)
5265e80de5eSkettenis 			return;
5275e80de5eSkettenis 		timeout_add_msec(&sc->sc_state_to, 1);
528fc69c4e1Skettenis 		return;
529fc69c4e1Skettenis 	}
530fc69c4e1Skettenis 
5315e80de5eSkettenis 	sc->sc_retry = 0;
5325e80de5eSkettenis 
5335e80de5eSkettenis 	if (sc->sc_state == LOM_STATE_CMD) {
5345e80de5eSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd);
5355e80de5eSkettenis 		sc->sc_state = LOM_STATE_DATA;
5365e80de5eSkettenis 		timeout_add_msec(&sc->sc_state_to, 250);
537fc69c4e1Skettenis 		return;
538fc69c4e1Skettenis 	}
539fc69c4e1Skettenis 
5405e80de5eSkettenis 	KASSERT(sc->sc_state == LOM_STATE_DATA);
5415e80de5eSkettenis 	if ((lc->lc_cmd & LOM_IDX_WRITE) == 0)
5425e80de5eSkettenis 		lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
5435e80de5eSkettenis 	else
5445e80de5eSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data);
5455e80de5eSkettenis 
5465e80de5eSkettenis 	TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
5475e80de5eSkettenis 
5485e80de5eSkettenis 	wakeup(lc);
5495e80de5eSkettenis 
5505e80de5eSkettenis 	if (!TAILQ_EMPTY(&sc->sc_queue)) {
5515e80de5eSkettenis 		sc->sc_state = LOM_STATE_CMD;
5525e80de5eSkettenis 		timeout_add_msec(&sc->sc_state_to, 1);
5535e80de5eSkettenis 		return;
5545e80de5eSkettenis 	}
5555e80de5eSkettenis 
5565e80de5eSkettenis 	sc->sc_state = LOM_STATE_IDLE;
557fc69c4e1Skettenis }
558fc69c4e1Skettenis 
55913d051d6Skettenis int
56013d051d6Skettenis lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
56113d051d6Skettenis {
5625f2dcfb1Skettenis 	uint8_t str;
5635f2dcfb1Skettenis 	int i;
5645f2dcfb1Skettenis 
5655f2dcfb1Skettenis 	/* Wait for input buffer to become available. */
5665f2dcfb1Skettenis 	for (i = 1000; i > 0; i--) {
56713d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
5685f2dcfb1Skettenis 		delay(10);
56913d051d6Skettenis 		if ((str & LOM2_STATUS_IBF) == 0)
57013d051d6Skettenis 			break;
57113d051d6Skettenis 	}
57213d051d6Skettenis 	if (i == 0)
57313d051d6Skettenis 		return (ETIMEDOUT);
57413d051d6Skettenis 
57513d051d6Skettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
57613d051d6Skettenis 
57713d051d6Skettenis 	/* Wait until the microcontroller fills output buffer. */
57813d051d6Skettenis 	for (i = 1000; i > 0; i--) {
57913d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
58013d051d6Skettenis 		delay(10);
58113d051d6Skettenis 		if (str & LOM2_STATUS_OBF)
58213d051d6Skettenis 			break;
58313d051d6Skettenis 	}
58413d051d6Skettenis 	if (i == 0)
58513d051d6Skettenis 		return (ETIMEDOUT);
58613d051d6Skettenis 
58713d051d6Skettenis 	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
58813d051d6Skettenis 	return (0);
58913d051d6Skettenis }
59013d051d6Skettenis 
59113d051d6Skettenis int
59213d051d6Skettenis lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
59313d051d6Skettenis {
59413d051d6Skettenis 	uint8_t str;
59513d051d6Skettenis 	int i;
59613d051d6Skettenis 
59713d051d6Skettenis 	/* Wait for input buffer to become available. */
59813d051d6Skettenis 	for (i = 1000; i > 0; i--) {
59913d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
60013d051d6Skettenis 		delay(10);
60113d051d6Skettenis 		if ((str & LOM2_STATUS_IBF) == 0)
6025f2dcfb1Skettenis 			break;
6035f2dcfb1Skettenis 	}
6045f2dcfb1Skettenis 	if (i == 0)
6055f2dcfb1Skettenis 		return (ETIMEDOUT);
6065f2dcfb1Skettenis 
6075f2dcfb1Skettenis 	if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
6085f2dcfb1Skettenis 		reg |= 0x80;
6095f2dcfb1Skettenis 
61013d051d6Skettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
6115f2dcfb1Skettenis 
6125f2dcfb1Skettenis 	/* Wait until the microcontroller fills output buffer. */
6135f2dcfb1Skettenis 	for (i = 1000; i > 0; i--) {
61413d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
6155f2dcfb1Skettenis 		delay(10);
61613d051d6Skettenis 		if (str & LOM2_STATUS_OBF)
6175f2dcfb1Skettenis 			break;
6185f2dcfb1Skettenis 	}
6195f2dcfb1Skettenis 	if (i == 0)
6205f2dcfb1Skettenis 		return (ETIMEDOUT);
6215f2dcfb1Skettenis 
62213d051d6Skettenis 	bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
6235f2dcfb1Skettenis 
6245f2dcfb1Skettenis 	/* Wait for input buffer to become available. */
6255f2dcfb1Skettenis 	for (i = 1000; i > 0; i--) {
62613d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
6275f2dcfb1Skettenis 		delay(10);
62813d051d6Skettenis 		if ((str & LOM2_STATUS_IBF) == 0)
6295f2dcfb1Skettenis 			break;
6305f2dcfb1Skettenis 	}
6315f2dcfb1Skettenis 	if (i == 0)
6325f2dcfb1Skettenis 		return (ETIMEDOUT);
6335f2dcfb1Skettenis 
63413d051d6Skettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val);
6355f2dcfb1Skettenis 
6365f2dcfb1Skettenis 	/* Wait until the microcontroller fills output buffer. */
6375f2dcfb1Skettenis 	for (i = 1000; i > 0; i--) {
63813d051d6Skettenis 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
6395f2dcfb1Skettenis 		delay(10);
64013d051d6Skettenis 		if (str & LOM2_STATUS_OBF)
6415f2dcfb1Skettenis 			break;
6425f2dcfb1Skettenis 	}
6435f2dcfb1Skettenis 	if (i == 0)
6445f2dcfb1Skettenis 		return (ETIMEDOUT);
6455f2dcfb1Skettenis 
64613d051d6Skettenis 	bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
6475f2dcfb1Skettenis 
6485f2dcfb1Skettenis 	/* If we switched spaces, remember the one we're in now. */
6495f2dcfb1Skettenis 	if (reg == LOM_IDX_CMD)
6505f2dcfb1Skettenis 		sc->sc_space = val;
6515f2dcfb1Skettenis 
6525f2dcfb1Skettenis 	return (0);
6535f2dcfb1Skettenis }
6545f2dcfb1Skettenis 
6555e80de5eSkettenis void
6565e80de5eSkettenis lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
6575e80de5eSkettenis {
6585e80de5eSkettenis 	KASSERT(lc->lc_cmd & LOM_IDX_WRITE);
6595e80de5eSkettenis 	lom2_write(sc, lc->lc_cmd, lc->lc_data);
6605e80de5eSkettenis }
6615e80de5eSkettenis 
6625f2dcfb1Skettenis int
6635f2dcfb1Skettenis lom_init_desc(struct lom_softc *sc)
6645f2dcfb1Skettenis {
6655f2dcfb1Skettenis 	uint8_t val;
66602222f5cSkettenis 	int i, j, k;
66702222f5cSkettenis 	int error;
6685f2dcfb1Skettenis 
66913d051d6Skettenis 	/* LOMlite doesn't provide sensor descriptions. */
67013d051d6Skettenis 	if (sc->sc_type < LOM_LOMLITE2)
67113d051d6Skettenis 		return (0);
67213d051d6Skettenis 
67302222f5cSkettenis 	/*
67402222f5cSkettenis 	 * Read temperature sensor names.
67502222f5cSkettenis 	 */
6765f2dcfb1Skettenis 	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP);
6775f2dcfb1Skettenis 	if (error)
6785f2dcfb1Skettenis 		return (error);
6795f2dcfb1Skettenis 
68002222f5cSkettenis 	i = 0;
68102222f5cSkettenis 	j = 0;
68202222f5cSkettenis 	k = LOM_IDX4_TEMP_NAME_START;
68302222f5cSkettenis 	while (k <= LOM_IDX4_TEMP_NAME_END) {
68402222f5cSkettenis 		error = lom_read(sc, k++, &val);
6855f2dcfb1Skettenis 		if (error)
6865f2dcfb1Skettenis 			goto fail;
6875f2dcfb1Skettenis 
6885f2dcfb1Skettenis 		if (val == 0xff)
6895f2dcfb1Skettenis 			break;
6905f2dcfb1Skettenis 
69113d051d6Skettenis 		if (j < sizeof (sc->sc_temp[i].desc) - 1)
69213d051d6Skettenis 			sc->sc_temp[i].desc[j++] = val;
69313d051d6Skettenis 
69402222f5cSkettenis 		if (val == '\0') {
6955f2dcfb1Skettenis 			i++;
69602222f5cSkettenis 			j = 0;
69702222f5cSkettenis 			if (i < sc->sc_num_temp)
69802222f5cSkettenis 				continue;
69902222f5cSkettenis 
70002222f5cSkettenis 			break;
70102222f5cSkettenis 		}
70202222f5cSkettenis 	}
70302222f5cSkettenis 
70402222f5cSkettenis 	/*
70502222f5cSkettenis 	 * Read fan names.
70602222f5cSkettenis 	 */
70702222f5cSkettenis 	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN);
70802222f5cSkettenis 	if (error)
70902222f5cSkettenis 		return (error);
71002222f5cSkettenis 
71102222f5cSkettenis 	i = 0;
71202222f5cSkettenis 	j = 0;
71302222f5cSkettenis 	k = LOM_IDX5_FAN_NAME_START;
71402222f5cSkettenis 	while (k <= LOM_IDX5_FAN_NAME_END) {
71502222f5cSkettenis 		error = lom_read(sc, k++, &val);
71602222f5cSkettenis 		if (error)
71702222f5cSkettenis 			goto fail;
71802222f5cSkettenis 
71902222f5cSkettenis 		if (val == 0xff)
72002222f5cSkettenis 			break;
72102222f5cSkettenis 
72213d051d6Skettenis 		if (j < sizeof (sc->sc_fan[i].desc) - 1)
72313d051d6Skettenis 			sc->sc_fan[i].desc[j++] = val;
72413d051d6Skettenis 
72502222f5cSkettenis 		if (val == '\0') {
72602222f5cSkettenis 			i++;
72702222f5cSkettenis 			j = 0;
72802222f5cSkettenis 			if (i < sc->sc_num_fan)
72902222f5cSkettenis 				continue;
73002222f5cSkettenis 
73102222f5cSkettenis 			break;
73202222f5cSkettenis 		}
7335f2dcfb1Skettenis 	}
7345f2dcfb1Skettenis 
7355f2dcfb1Skettenis fail:
7365f2dcfb1Skettenis 	lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC);
7375f2dcfb1Skettenis 	return (error);
7385f2dcfb1Skettenis }
7395f2dcfb1Skettenis 
7402613757eSkettenis void
7412613757eSkettenis lom_refresh(void *arg)
7422613757eSkettenis {
7432613757eSkettenis 	struct lom_softc *sc = arg;
7442613757eSkettenis 	uint8_t val;
74502222f5cSkettenis 	int i;
7462613757eSkettenis 
74702222f5cSkettenis 	for (i = 0; i < sc->sc_num_fan; i++) {
74802222f5cSkettenis 		if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) {
74902222f5cSkettenis 			sc->sc_fan[i].flags |= SENSOR_FINVALID;
75002222f5cSkettenis 			continue;
75102222f5cSkettenis 		}
75202222f5cSkettenis 
75302222f5cSkettenis 		sc->sc_fan[i].value = (60 * sc->sc_fan_cal[i] * val) / 100;
754*df54a7c0Skettenis 		if (val < sc->sc_fan_low[i])
755*df54a7c0Skettenis 			sc->sc_fan[i].status = SENSOR_S_CRIT;
756*df54a7c0Skettenis 		else
757*df54a7c0Skettenis 			sc->sc_fan[i].status = SENSOR_S_OK;
75802222f5cSkettenis 		sc->sc_fan[i].flags &= ~SENSOR_FINVALID;
75902222f5cSkettenis 	}
7606801a748Skettenis 
76178eeb547Skettenis 	for (i = 0; i < sc->sc_num_psu; i++) {
76278eeb547Skettenis 		if (lom_read(sc, LOM_IDX_PSU1 + i, &val) ||
76378eeb547Skettenis 		    !ISSET(val, LOM_PSU_PRESENT)) {
76478eeb547Skettenis 			sc->sc_psu[i].flags |= SENSOR_FINVALID;
76578eeb547Skettenis 			continue;
76678eeb547Skettenis 		}
76778eeb547Skettenis 
76878eeb547Skettenis 		if (val & LOM_PSU_STANDBY) {
76978eeb547Skettenis 			sc->sc_psu[i].value = 0;
77078eeb547Skettenis 			sc->sc_psu[i].status = SENSOR_S_UNSPEC;
77178eeb547Skettenis 		} else {
77278eeb547Skettenis 			sc->sc_psu[i].value = 1;
77378eeb547Skettenis 			if (ISSET(val, LOM_PSU_INPUTA) &&
77478eeb547Skettenis 			    ISSET(val, LOM_PSU_INPUTB) &&
77578eeb547Skettenis 			    ISSET(val, LOM_PSU_OUTPUT))
77678eeb547Skettenis 				sc->sc_psu[i].status = SENSOR_S_OK;
77778eeb547Skettenis 			else
77878eeb547Skettenis 				sc->sc_psu[i].status = SENSOR_S_CRIT;
77978eeb547Skettenis 		}
78078eeb547Skettenis 		sc->sc_psu[i].flags &= ~SENSOR_FINVALID;
78178eeb547Skettenis 	}
78278eeb547Skettenis 
78378eeb547Skettenis 	for (i = 0; i < sc->sc_num_temp; i++) {
78478eeb547Skettenis 		if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) {
78578eeb547Skettenis 			sc->sc_temp[i].flags |= SENSOR_FINVALID;
78678eeb547Skettenis 			continue;
78778eeb547Skettenis 		}
78878eeb547Skettenis 
78978eeb547Skettenis 		sc->sc_temp[i].value = val * 1000000 + 273150000;
79078eeb547Skettenis 		sc->sc_temp[i].flags &= ~SENSOR_FINVALID;
79178eeb547Skettenis 	}
79278eeb547Skettenis 
7936801a748Skettenis 	/*
7946801a748Skettenis 	 * If our hostname is set and differs from what's stored in
7956801a748Skettenis 	 * the LOM, write the new hostname back to the LOM.  Note that
7966801a748Skettenis 	 * we include the terminating NUL when writing the hostname
797fc69c4e1Skettenis 	 * back to the LOM, otherwise the LOM will print any trailing
7986801a748Skettenis 	 * garbage.
7996801a748Skettenis 	 */
8006801a748Skettenis 	if (hostnamelen > 0 &&
8016801a748Skettenis 	    strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) {
80213d051d6Skettenis 		if (sc->sc_type < LOM_LOMLITE2)
80313d051d6Skettenis 			lom1_write_hostname(sc);
80413d051d6Skettenis 		else
80513d051d6Skettenis 			lom2_write_hostname(sc);
8066801a748Skettenis 		strlcpy(sc->sc_hostname, hostname, sizeof(hostname));
8076801a748Skettenis 	}
8082613757eSkettenis }
809877407b4Skettenis 
810877407b4Skettenis void
81113d051d6Skettenis lom1_write_hostname(struct lom_softc *sc)
81213d051d6Skettenis {
81313d051d6Skettenis 	char name[LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1];
81413d051d6Skettenis 	char *p;
81513d051d6Skettenis 	int i;
81613d051d6Skettenis 
81713d051d6Skettenis 	/*
81813d051d6Skettenis 	 * LOMlite generally doesn't have enough space to store the
81913d051d6Skettenis 	 * fully qualified hostname.  If the hostname is too long,
82013d051d6Skettenis 	 * strip off the domain name.
82113d051d6Skettenis 	 */
82213d051d6Skettenis 	strlcpy(name, hostname, sizeof(name));
82313d051d6Skettenis 	if (hostnamelen > sizeof(name)) {
82413d051d6Skettenis 		p = strchr(name, '.');
82513d051d6Skettenis 		if (p)
82613d051d6Skettenis 			*p = '\0';
82713d051d6Skettenis 	}
82813d051d6Skettenis 
82913d051d6Skettenis 	for (i = 0; i < strlen(name) + 1; i++)
8305e80de5eSkettenis 		if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i]))
8315e80de5eSkettenis 			break;
83213d051d6Skettenis }
83313d051d6Skettenis 
83413d051d6Skettenis void
83513d051d6Skettenis lom2_write_hostname(struct lom_softc *sc)
83613d051d6Skettenis {
83713d051d6Skettenis 	int i;
83813d051d6Skettenis 
83913d051d6Skettenis 	lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1);
84013d051d6Skettenis 	for (i = 0; i < hostnamelen + 1; i++)
84113d051d6Skettenis 		lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]);
84213d051d6Skettenis }
84313d051d6Skettenis 
84413d051d6Skettenis void
845877407b4Skettenis lom_wdog_pat(void *arg)
846877407b4Skettenis {
847877407b4Skettenis 	struct lom_softc *sc;
848877407b4Skettenis 
849877407b4Skettenis 	/* Pat the dog. */
8505e80de5eSkettenis 	sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
8515e80de5eSkettenis 	sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
8525e80de5eSkettenis 	lom_queue_cmd(sc, &sc->sc_wdog_pat);
853877407b4Skettenis 
854877407b4Skettenis 	timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
855877407b4Skettenis }
856877407b4Skettenis 
857877407b4Skettenis int
858877407b4Skettenis lom_wdog_cb(void *arg, int period)
859877407b4Skettenis {
860877407b4Skettenis 	struct lom_softc *sc = arg;
861877407b4Skettenis 
862fc69c4e1Skettenis 	if (period > LOM_WDOG_TIME_MAX)
863fc69c4e1Skettenis 		period = LOM_WDOG_TIME_MAX;
864877407b4Skettenis 	else if (period < 0)
865877407b4Skettenis 		period = 0;
866877407b4Skettenis 
867877407b4Skettenis 	if (period == 0) {
868877407b4Skettenis 		if (sc->sc_wdog_period != 0) {
869877407b4Skettenis 			/* Stop watchdog from resetting the machine. */
8705223c73eSkettenis 			sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
8715223c73eSkettenis 			lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
872877407b4Skettenis 
873877407b4Skettenis 			lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
874877407b4Skettenis 			timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
875877407b4Skettenis 		}
876877407b4Skettenis 	} else {
877877407b4Skettenis 		if (sc->sc_wdog_period != period) {
878877407b4Skettenis 			/* Set new timeout. */
879877407b4Skettenis 			lom_write(sc, LOM_IDX_WDOG_TIME, period);
880877407b4Skettenis 		}
881877407b4Skettenis 		if (sc->sc_wdog_period == 0) {
882877407b4Skettenis 			/* Make watchdog reset the machine. */
8835223c73eSkettenis 			sc->sc_wdog_ctl |= LOM_WDOG_RESET;
8845223c73eSkettenis 			lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
885877407b4Skettenis 
886877407b4Skettenis 			timeout_del(&sc->sc_wdog_to);
887877407b4Skettenis 		} else {
888877407b4Skettenis 			/* Pat the dog. */
8895e80de5eSkettenis 			sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
8905e80de5eSkettenis 			sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
8915e80de5eSkettenis 			lom_queue_cmd(sc, &sc->sc_wdog_pat);
892877407b4Skettenis 		}
893877407b4Skettenis 	}
894877407b4Skettenis 	sc->sc_wdog_period = period;
895877407b4Skettenis 
896877407b4Skettenis 	return (period);
897877407b4Skettenis }
898