1*a4f1f624Skettenis /* $OpenBSD: lom.c,v 1.17 2009/10/31 19:13:37 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 *); 194*a4f1f624Skettenis void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *); 19513d051d6Skettenis int lom1_read(struct lom_softc *, uint8_t, uint8_t *); 19613d051d6Skettenis int lom1_write(struct lom_softc *, uint8_t, uint8_t); 1975e80de5eSkettenis int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *); 1985e80de5eSkettenis int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t); 1995e80de5eSkettenis void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *); 2005e80de5eSkettenis void lom1_dequeue_cmd(struct lom_softc *, struct lom_cmd *); 2015e80de5eSkettenis void lom1_process_queue(void *); 2025e80de5eSkettenis void lom1_process_queue_locked(struct lom_softc *); 20313d051d6Skettenis int lom2_read(struct lom_softc *, uint8_t, uint8_t *); 20413d051d6Skettenis int lom2_write(struct lom_softc *, uint8_t, uint8_t); 2055e80de5eSkettenis void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *); 2062613757eSkettenis 2075f2dcfb1Skettenis int lom_init_desc(struct lom_softc *sc); 2082613757eSkettenis void lom_refresh(void *); 20913d051d6Skettenis void lom1_write_hostname(struct lom_softc *); 21013d051d6Skettenis void lom2_write_hostname(struct lom_softc *); 2112613757eSkettenis 212877407b4Skettenis void lom_wdog_pat(void *); 213877407b4Skettenis int lom_wdog_cb(void *, int); 214877407b4Skettenis 2152613757eSkettenis int 2162613757eSkettenis lom_match(struct device *parent, void *match, void *aux) 2172613757eSkettenis { 2182613757eSkettenis struct ebus_attach_args *ea = aux; 2192613757eSkettenis 220fc69c4e1Skettenis if (strcmp(ea->ea_name, "SUNW,lom") == 0 || 221fc69c4e1Skettenis strcmp(ea->ea_name, "SUNW,lomh") == 0) 2222613757eSkettenis return (1); 2232613757eSkettenis 2242613757eSkettenis return (0); 2252613757eSkettenis } 2262613757eSkettenis 2272613757eSkettenis void 2282613757eSkettenis lom_attach(struct device *parent, struct device *self, void *aux) 2292613757eSkettenis { 2302613757eSkettenis struct lom_softc *sc = (void *)self; 2312613757eSkettenis struct ebus_attach_args *ea = aux; 23202222f5cSkettenis uint8_t reg, fw_rev, config, config2, config3; 23313d051d6Skettenis uint8_t cal, low; 23402222f5cSkettenis int i; 2352613757eSkettenis 23613d051d6Skettenis if (strcmp(ea->ea_name, "SUNW,lomh") == 0) 23713d051d6Skettenis sc->sc_type = LOM_LOMLITE2; 23813d051d6Skettenis 239d151cb6cSkettenis if (ebus_bus_map(ea->ea_iotag, 0, 2402613757eSkettenis EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 241d151cb6cSkettenis ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 242d151cb6cSkettenis sc->sc_iot = ea->ea_iotag; 243d151cb6cSkettenis } else if (ebus_bus_map(ea->ea_memtag, 0, 244d151cb6cSkettenis EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 245d151cb6cSkettenis ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 246d151cb6cSkettenis sc->sc_iot = ea->ea_memtag; 247d151cb6cSkettenis } else { 2482613757eSkettenis printf(": can't map register space\n"); 2492613757eSkettenis return; 2502613757eSkettenis } 2512613757eSkettenis 25213d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) { 25313d051d6Skettenis /* XXX Magic */ 25413d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0); 25513d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca); 256fc69c4e1Skettenis 2575e80de5eSkettenis TAILQ_INIT(&sc->sc_queue); 2585e80de5eSkettenis mtx_init(&sc->sc_queue_mtx, IPL_BIO); 2595e80de5eSkettenis timeout_set(&sc->sc_state_to, lom1_process_queue, sc); 26013d051d6Skettenis } 26113d051d6Skettenis 2622613757eSkettenis if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 || 2632613757eSkettenis lom_read(sc, LOM_IDX_PROBEAA, ®) || reg != 0xaa || 26402222f5cSkettenis lom_read(sc, LOM_IDX_FW_REV, &fw_rev) || 26513d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG, &config)) 26602222f5cSkettenis { 2672613757eSkettenis printf(": not responding\n"); 2682613757eSkettenis return; 2692613757eSkettenis } 2702613757eSkettenis 27113d051d6Skettenis config2 = config3 = 0; 27213d051d6Skettenis if (sc->sc_type >= LOM_LOMLITE2) { 27313d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG2, &config2); 27413d051d6Skettenis lom_read(sc, LOM_IDX_CONFIG3, &config3); 27513d051d6Skettenis } 27613d051d6Skettenis 27702222f5cSkettenis sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN); 27802222f5cSkettenis sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU); 27902222f5cSkettenis sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP); 28002222f5cSkettenis 28102222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) { 28202222f5cSkettenis if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) || 28302222f5cSkettenis lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) { 28402222f5cSkettenis printf(": can't read fan information\n"); 28502222f5cSkettenis return; 28602222f5cSkettenis } 28702222f5cSkettenis sc->sc_fan_cal[i] = cal; 28802222f5cSkettenis sc->sc_fan_low[i] = low; 28902222f5cSkettenis } 29002222f5cSkettenis 2912613757eSkettenis /* Initialize sensor data. */ 2922613757eSkettenis strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 2932613757eSkettenis sizeof(sc->sc_sensordev.xname)); 29402222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) { 29502222f5cSkettenis sc->sc_fan[i].type = SENSOR_FANRPM; 29602222f5cSkettenis sensor_attach(&sc->sc_sensordev, &sc->sc_fan[i]); 29713d051d6Skettenis snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc), 29813d051d6Skettenis "fan%d", i + 1); 29902222f5cSkettenis } 30078eeb547Skettenis for (i = 0; i < sc->sc_num_psu; i++) { 30178eeb547Skettenis sc->sc_psu[i].type = SENSOR_INDICATOR; 30278eeb547Skettenis sensor_attach(&sc->sc_sensordev, &sc->sc_psu[i]); 30378eeb547Skettenis snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc), 30478eeb547Skettenis "PSU%d", i + 1); 30578eeb547Skettenis } 30602222f5cSkettenis for (i = 0; i < sc->sc_num_temp; i++) { 30702222f5cSkettenis sc->sc_temp[i].type = SENSOR_TEMP; 30802222f5cSkettenis sensor_attach(&sc->sc_sensordev, &sc->sc_temp[i]); 30902222f5cSkettenis } 3105f2dcfb1Skettenis if (lom_init_desc(sc)) { 3115f2dcfb1Skettenis printf(": can't read sensor names\n"); 3125f2dcfb1Skettenis return; 3135f2dcfb1Skettenis } 3142613757eSkettenis 3152613757eSkettenis if (sensor_task_register(sc, lom_refresh, 5) == NULL) { 3162613757eSkettenis printf(": unable to register update task\n"); 3172613757eSkettenis return; 3182613757eSkettenis } 3192613757eSkettenis 3202613757eSkettenis sensordev_install(&sc->sc_sensordev); 3212613757eSkettenis 322877407b4Skettenis /* 323877407b4Skettenis * We configure the watchdog to turn on the fault LED when the 324877407b4Skettenis * watchdog timer expires. We run our own timeout to pat it 325877407b4Skettenis * such that this won't happen unless the kernel hangs. When 326877407b4Skettenis * the watchdog is explicitly configured using sysctl(8), we 327877407b4Skettenis * reconfigure it to reset the machine and let the standard 328877407b4Skettenis * watchdog(4) machinery take over. 329877407b4Skettenis */ 330877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 3315223c73eSkettenis lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl); 3325223c73eSkettenis sc->sc_wdog_ctl &= ~LOM_WDOG_RESET; 3335223c73eSkettenis sc->sc_wdog_ctl |= LOM_WDOG_ENABLE; 3345223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 335877407b4Skettenis timeout_set(&sc->sc_wdog_to, lom_wdog_pat, sc); 336877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 337877407b4Skettenis 338877407b4Skettenis wdog_register(sc, lom_wdog_cb); 339877407b4Skettenis 340e6d8f4d1Skettenis printf(": %s rev %d.%d\n", 341e6d8f4d1Skettenis sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2", 342e6d8f4d1Skettenis fw_rev >> 4, fw_rev & 0x0f); 3432613757eSkettenis } 3442613757eSkettenis 3452613757eSkettenis int 3462613757eSkettenis lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 3472613757eSkettenis { 34813d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) 34913d051d6Skettenis return lom1_read(sc, reg, val); 35013d051d6Skettenis else 35113d051d6Skettenis return lom2_read(sc, reg, val); 3522613757eSkettenis } 3532613757eSkettenis 3545f2dcfb1Skettenis int 3555f2dcfb1Skettenis lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 3565f2dcfb1Skettenis { 35713d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) 35813d051d6Skettenis return lom1_write(sc, reg, val); 35913d051d6Skettenis else 36013d051d6Skettenis return lom2_write(sc, reg, val); 36113d051d6Skettenis } 36213d051d6Skettenis 3635e80de5eSkettenis void 3645e80de5eSkettenis lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 3655e80de5eSkettenis { 3665e80de5eSkettenis if (sc->sc_type < LOM_LOMLITE2) 3675e80de5eSkettenis return lom1_queue_cmd(sc, lc); 3685e80de5eSkettenis else 3695e80de5eSkettenis return lom2_queue_cmd(sc, lc); 3705e80de5eSkettenis } 3715e80de5eSkettenis 372*a4f1f624Skettenis void 373*a4f1f624Skettenis lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 374*a4f1f624Skettenis { 375*a4f1f624Skettenis if (sc->sc_type < LOM_LOMLITE2) 376*a4f1f624Skettenis return lom1_dequeue_cmd(sc, lc); 377*a4f1f624Skettenis } 378*a4f1f624Skettenis 37913d051d6Skettenis int 38013d051d6Skettenis lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 38113d051d6Skettenis { 3825e80de5eSkettenis struct lom_cmd lc; 383fc69c4e1Skettenis int error; 384fc69c4e1Skettenis 385fc69c4e1Skettenis if (cold) 386fc69c4e1Skettenis return lom1_read_polled(sc, reg, val); 387fc69c4e1Skettenis 3885e80de5eSkettenis lc.lc_cmd = reg; 3895e80de5eSkettenis lc.lc_data = 0xff; 3905e80de5eSkettenis lom1_queue_cmd(sc, &lc); 391fc69c4e1Skettenis 3925e80de5eSkettenis error = tsleep(&lc, PZERO, "lomrd", hz); 3935e80de5eSkettenis if (error) 3945e80de5eSkettenis lom1_dequeue_cmd(sc, &lc); 395fc69c4e1Skettenis 3965e80de5eSkettenis *val = lc.lc_data; 3975e80de5eSkettenis 3985e80de5eSkettenis return (error); 3995e80de5eSkettenis } 4005e80de5eSkettenis 4015e80de5eSkettenis int 4025e80de5eSkettenis lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 4035e80de5eSkettenis { 4045e80de5eSkettenis struct lom_cmd lc; 4055e80de5eSkettenis int error; 4065e80de5eSkettenis 4075e80de5eSkettenis if (cold) 4085e80de5eSkettenis return lom1_write_polled(sc, reg, val); 4095e80de5eSkettenis 4105e80de5eSkettenis lc.lc_cmd = reg | LOM_IDX_WRITE; 4115e80de5eSkettenis lc.lc_data = val; 4125e80de5eSkettenis lom1_queue_cmd(sc, &lc); 4135e80de5eSkettenis 4148fe2a92fSkettenis error = tsleep(&lc, PZERO, "lomwr", 2 * hz); 4155e80de5eSkettenis if (error) 4165e80de5eSkettenis lom1_dequeue_cmd(sc, &lc); 417fc69c4e1Skettenis 418fc69c4e1Skettenis return (error); 419fc69c4e1Skettenis } 420fc69c4e1Skettenis 421fc69c4e1Skettenis int 422fc69c4e1Skettenis lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 423fc69c4e1Skettenis { 42413d051d6Skettenis uint8_t str; 42513d051d6Skettenis int i; 42613d051d6Skettenis 42713d051d6Skettenis /* Wait for input buffer to become available. */ 4283c40421dSkettenis for (i = 30; i > 0; i--) { 42913d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 4303c40421dSkettenis delay(1000); 43113d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0) 43213d051d6Skettenis break; 43313d051d6Skettenis } 43413d051d6Skettenis if (i == 0) 43513d051d6Skettenis return (ETIMEDOUT); 43613d051d6Skettenis 43713d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 43813d051d6Skettenis 43913d051d6Skettenis /* Wait until the microcontroller fills output buffer. */ 4403c40421dSkettenis for (i = 30; i > 0; i--) { 44113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 4423c40421dSkettenis delay(1000); 44313d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0) 44413d051d6Skettenis break; 44513d051d6Skettenis } 44613d051d6Skettenis if (i == 0) 44713d051d6Skettenis return (ETIMEDOUT); 44813d051d6Skettenis 44913d051d6Skettenis *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 45013d051d6Skettenis return (0); 45113d051d6Skettenis } 45213d051d6Skettenis 45313d051d6Skettenis int 4545e80de5eSkettenis lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 45513d051d6Skettenis { 45613d051d6Skettenis uint8_t str; 45713d051d6Skettenis int i; 45813d051d6Skettenis 45913d051d6Skettenis /* Wait for input buffer to become available. */ 4603c40421dSkettenis for (i = 30; i > 0; i--) { 46113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 4623c40421dSkettenis delay(1000); 46313d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0) 46413d051d6Skettenis break; 46513d051d6Skettenis } 46613d051d6Skettenis if (i == 0) 46713d051d6Skettenis return (ETIMEDOUT); 46813d051d6Skettenis 4695e80de5eSkettenis reg |= LOM_IDX_WRITE; 4705e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 47113d051d6Skettenis 47213d051d6Skettenis /* Wait until the microcontroller fills output buffer. */ 4733c40421dSkettenis for (i = 30; i > 0; i--) { 47413d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 4753c40421dSkettenis delay(1000); 47613d051d6Skettenis if ((str & LOM1_STATUS_BUSY) == 0) 47713d051d6Skettenis break; 47813d051d6Skettenis } 47913d051d6Skettenis if (i == 0) 48013d051d6Skettenis return (ETIMEDOUT); 48113d051d6Skettenis 48213d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val); 48313d051d6Skettenis 48413d051d6Skettenis return (0); 48513d051d6Skettenis } 48613d051d6Skettenis 487fc69c4e1Skettenis void 4885e80de5eSkettenis lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 4895e80de5eSkettenis { 4905e80de5eSkettenis mtx_enter(&sc->sc_queue_mtx); 4915e80de5eSkettenis TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 4925e80de5eSkettenis if (sc->sc_state == LOM_STATE_IDLE) { 4935e80de5eSkettenis sc->sc_state = LOM_STATE_CMD; 4945e80de5eSkettenis lom1_process_queue_locked(sc); 4955e80de5eSkettenis } 4965e80de5eSkettenis mtx_leave(&sc->sc_queue_mtx); 4975e80de5eSkettenis } 4985e80de5eSkettenis 4995e80de5eSkettenis void 5005e80de5eSkettenis lom1_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 5015e80de5eSkettenis { 5025e80de5eSkettenis struct lom_cmd *lcp; 5035e80de5eSkettenis 5045e80de5eSkettenis mtx_enter(&sc->sc_queue_mtx); 5055e80de5eSkettenis TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 5065e80de5eSkettenis if (lcp == lc) { 5075e80de5eSkettenis TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 5085e80de5eSkettenis break; 5095e80de5eSkettenis } 5105e80de5eSkettenis } 5115e80de5eSkettenis mtx_leave(&sc->sc_queue_mtx); 5125e80de5eSkettenis } 5135e80de5eSkettenis 5145e80de5eSkettenis void 5155e80de5eSkettenis lom1_process_queue(void *arg) 516fc69c4e1Skettenis { 517fc69c4e1Skettenis struct lom_softc *sc = arg; 5185e80de5eSkettenis 5195e80de5eSkettenis mtx_enter(&sc->sc_queue_mtx); 5205e80de5eSkettenis lom1_process_queue_locked(sc); 5215e80de5eSkettenis mtx_leave(&sc->sc_queue_mtx); 5225e80de5eSkettenis } 5235e80de5eSkettenis 5245e80de5eSkettenis void 5255e80de5eSkettenis lom1_process_queue_locked(struct lom_softc *sc) 5265e80de5eSkettenis { 5275e80de5eSkettenis struct lom_cmd *lc; 528fc69c4e1Skettenis uint8_t str; 529fc69c4e1Skettenis 5305e80de5eSkettenis lc = TAILQ_FIRST(&sc->sc_queue); 5318fe2a92fSkettenis if (lc == NULL) { 5328fe2a92fSkettenis sc->sc_state = LOM_STATE_IDLE; 5338fe2a92fSkettenis return; 5348fe2a92fSkettenis } 5355e80de5eSkettenis 536fc69c4e1Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 537fc69c4e1Skettenis if (str & LOM1_STATUS_BUSY) { 5388fe2a92fSkettenis if (sc->sc_retry++ < 30) { 5395e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 1); 540fc69c4e1Skettenis return; 541fc69c4e1Skettenis } 542fc69c4e1Skettenis 5438fe2a92fSkettenis /* 5448fe2a92fSkettenis * Looks like the microcontroller got wedged. Unwedge 5458fe2a92fSkettenis * it by writing this magic value. Give it some time 5468fe2a92fSkettenis * to recover. 5478fe2a92fSkettenis */ 5488fe2a92fSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac); 5498fe2a92fSkettenis timeout_add_msec(&sc->sc_state_to, 1000); 5508fe2a92fSkettenis sc->sc_state = LOM_STATE_CMD; 5518fe2a92fSkettenis return; 5528fe2a92fSkettenis } 5538fe2a92fSkettenis 5545e80de5eSkettenis sc->sc_retry = 0; 5555e80de5eSkettenis 5565e80de5eSkettenis if (sc->sc_state == LOM_STATE_CMD) { 5575e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd); 5585e80de5eSkettenis sc->sc_state = LOM_STATE_DATA; 5595e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 250); 560fc69c4e1Skettenis return; 561fc69c4e1Skettenis } 562fc69c4e1Skettenis 5635e80de5eSkettenis KASSERT(sc->sc_state == LOM_STATE_DATA); 5645e80de5eSkettenis if ((lc->lc_cmd & LOM_IDX_WRITE) == 0) 5655e80de5eSkettenis lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 5665e80de5eSkettenis else 5675e80de5eSkettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data); 5685e80de5eSkettenis 5695e80de5eSkettenis TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 5705e80de5eSkettenis 5715e80de5eSkettenis wakeup(lc); 5725e80de5eSkettenis 5735e80de5eSkettenis if (!TAILQ_EMPTY(&sc->sc_queue)) { 5745e80de5eSkettenis sc->sc_state = LOM_STATE_CMD; 5755e80de5eSkettenis timeout_add_msec(&sc->sc_state_to, 1); 5765e80de5eSkettenis return; 5775e80de5eSkettenis } 5785e80de5eSkettenis 5795e80de5eSkettenis sc->sc_state = LOM_STATE_IDLE; 580fc69c4e1Skettenis } 581fc69c4e1Skettenis 58213d051d6Skettenis int 58313d051d6Skettenis lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 58413d051d6Skettenis { 5855f2dcfb1Skettenis uint8_t str; 5865f2dcfb1Skettenis int i; 5875f2dcfb1Skettenis 5885f2dcfb1Skettenis /* Wait for input buffer to become available. */ 5895f2dcfb1Skettenis for (i = 1000; i > 0; i--) { 59013d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 5915f2dcfb1Skettenis delay(10); 59213d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0) 59313d051d6Skettenis break; 59413d051d6Skettenis } 59513d051d6Skettenis if (i == 0) 59613d051d6Skettenis return (ETIMEDOUT); 59713d051d6Skettenis 59813d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 59913d051d6Skettenis 60013d051d6Skettenis /* Wait until the microcontroller fills output buffer. */ 60113d051d6Skettenis for (i = 1000; i > 0; i--) { 60213d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 60313d051d6Skettenis delay(10); 60413d051d6Skettenis if (str & LOM2_STATUS_OBF) 60513d051d6Skettenis break; 60613d051d6Skettenis } 60713d051d6Skettenis if (i == 0) 60813d051d6Skettenis return (ETIMEDOUT); 60913d051d6Skettenis 61013d051d6Skettenis *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 61113d051d6Skettenis return (0); 61213d051d6Skettenis } 61313d051d6Skettenis 61413d051d6Skettenis int 61513d051d6Skettenis lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 61613d051d6Skettenis { 61713d051d6Skettenis uint8_t str; 61813d051d6Skettenis int i; 61913d051d6Skettenis 62013d051d6Skettenis /* Wait for input buffer to become available. */ 62113d051d6Skettenis for (i = 1000; i > 0; i--) { 62213d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 62313d051d6Skettenis delay(10); 62413d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0) 6255f2dcfb1Skettenis break; 6265f2dcfb1Skettenis } 6275f2dcfb1Skettenis if (i == 0) 6285f2dcfb1Skettenis return (ETIMEDOUT); 6295f2dcfb1Skettenis 6305f2dcfb1Skettenis if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD) 6315f2dcfb1Skettenis reg |= 0x80; 6325f2dcfb1Skettenis 63313d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 6345f2dcfb1Skettenis 6355f2dcfb1Skettenis /* Wait until the microcontroller fills output buffer. */ 6365f2dcfb1Skettenis for (i = 1000; i > 0; i--) { 63713d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 6385f2dcfb1Skettenis delay(10); 63913d051d6Skettenis if (str & LOM2_STATUS_OBF) 6405f2dcfb1Skettenis break; 6415f2dcfb1Skettenis } 6425f2dcfb1Skettenis if (i == 0) 6435f2dcfb1Skettenis return (ETIMEDOUT); 6445f2dcfb1Skettenis 64513d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 6465f2dcfb1Skettenis 6475f2dcfb1Skettenis /* Wait for input buffer to become available. */ 6485f2dcfb1Skettenis for (i = 1000; i > 0; i--) { 64913d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 6505f2dcfb1Skettenis delay(10); 65113d051d6Skettenis if ((str & LOM2_STATUS_IBF) == 0) 6525f2dcfb1Skettenis break; 6535f2dcfb1Skettenis } 6545f2dcfb1Skettenis if (i == 0) 6555f2dcfb1Skettenis return (ETIMEDOUT); 6565f2dcfb1Skettenis 65713d051d6Skettenis bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val); 6585f2dcfb1Skettenis 6595f2dcfb1Skettenis /* Wait until the microcontroller fills output buffer. */ 6605f2dcfb1Skettenis for (i = 1000; i > 0; i--) { 66113d051d6Skettenis str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 6625f2dcfb1Skettenis delay(10); 66313d051d6Skettenis if (str & LOM2_STATUS_OBF) 6645f2dcfb1Skettenis break; 6655f2dcfb1Skettenis } 6665f2dcfb1Skettenis if (i == 0) 6675f2dcfb1Skettenis return (ETIMEDOUT); 6685f2dcfb1Skettenis 66913d051d6Skettenis bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 6705f2dcfb1Skettenis 6715f2dcfb1Skettenis /* If we switched spaces, remember the one we're in now. */ 6725f2dcfb1Skettenis if (reg == LOM_IDX_CMD) 6735f2dcfb1Skettenis sc->sc_space = val; 6745f2dcfb1Skettenis 6755f2dcfb1Skettenis return (0); 6765f2dcfb1Skettenis } 6775f2dcfb1Skettenis 6785e80de5eSkettenis void 6795e80de5eSkettenis lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 6805e80de5eSkettenis { 6815e80de5eSkettenis KASSERT(lc->lc_cmd & LOM_IDX_WRITE); 6825e80de5eSkettenis lom2_write(sc, lc->lc_cmd, lc->lc_data); 6835e80de5eSkettenis } 6845e80de5eSkettenis 6855f2dcfb1Skettenis int 6865f2dcfb1Skettenis lom_init_desc(struct lom_softc *sc) 6875f2dcfb1Skettenis { 6885f2dcfb1Skettenis uint8_t val; 68902222f5cSkettenis int i, j, k; 69002222f5cSkettenis int error; 6915f2dcfb1Skettenis 69213d051d6Skettenis /* LOMlite doesn't provide sensor descriptions. */ 69313d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) 69413d051d6Skettenis return (0); 69513d051d6Skettenis 69602222f5cSkettenis /* 69702222f5cSkettenis * Read temperature sensor names. 69802222f5cSkettenis */ 6995f2dcfb1Skettenis error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP); 7005f2dcfb1Skettenis if (error) 7015f2dcfb1Skettenis return (error); 7025f2dcfb1Skettenis 70302222f5cSkettenis i = 0; 70402222f5cSkettenis j = 0; 70502222f5cSkettenis k = LOM_IDX4_TEMP_NAME_START; 70602222f5cSkettenis while (k <= LOM_IDX4_TEMP_NAME_END) { 70702222f5cSkettenis error = lom_read(sc, k++, &val); 7085f2dcfb1Skettenis if (error) 7095f2dcfb1Skettenis goto fail; 7105f2dcfb1Skettenis 7115f2dcfb1Skettenis if (val == 0xff) 7125f2dcfb1Skettenis break; 7135f2dcfb1Skettenis 71413d051d6Skettenis if (j < sizeof (sc->sc_temp[i].desc) - 1) 71513d051d6Skettenis sc->sc_temp[i].desc[j++] = val; 71613d051d6Skettenis 71702222f5cSkettenis if (val == '\0') { 7185f2dcfb1Skettenis i++; 71902222f5cSkettenis j = 0; 72002222f5cSkettenis if (i < sc->sc_num_temp) 72102222f5cSkettenis continue; 72202222f5cSkettenis 72302222f5cSkettenis break; 72402222f5cSkettenis } 72502222f5cSkettenis } 72602222f5cSkettenis 72702222f5cSkettenis /* 72802222f5cSkettenis * Read fan names. 72902222f5cSkettenis */ 73002222f5cSkettenis error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN); 73102222f5cSkettenis if (error) 73202222f5cSkettenis return (error); 73302222f5cSkettenis 73402222f5cSkettenis i = 0; 73502222f5cSkettenis j = 0; 73602222f5cSkettenis k = LOM_IDX5_FAN_NAME_START; 73702222f5cSkettenis while (k <= LOM_IDX5_FAN_NAME_END) { 73802222f5cSkettenis error = lom_read(sc, k++, &val); 73902222f5cSkettenis if (error) 74002222f5cSkettenis goto fail; 74102222f5cSkettenis 74202222f5cSkettenis if (val == 0xff) 74302222f5cSkettenis break; 74402222f5cSkettenis 74513d051d6Skettenis if (j < sizeof (sc->sc_fan[i].desc) - 1) 74613d051d6Skettenis sc->sc_fan[i].desc[j++] = val; 74713d051d6Skettenis 74802222f5cSkettenis if (val == '\0') { 74902222f5cSkettenis i++; 75002222f5cSkettenis j = 0; 75102222f5cSkettenis if (i < sc->sc_num_fan) 75202222f5cSkettenis continue; 75302222f5cSkettenis 75402222f5cSkettenis break; 75502222f5cSkettenis } 7565f2dcfb1Skettenis } 7575f2dcfb1Skettenis 7585f2dcfb1Skettenis fail: 7595f2dcfb1Skettenis lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC); 7605f2dcfb1Skettenis return (error); 7615f2dcfb1Skettenis } 7625f2dcfb1Skettenis 7632613757eSkettenis void 7642613757eSkettenis lom_refresh(void *arg) 7652613757eSkettenis { 7662613757eSkettenis struct lom_softc *sc = arg; 7672613757eSkettenis uint8_t val; 76802222f5cSkettenis int i; 7692613757eSkettenis 77002222f5cSkettenis for (i = 0; i < sc->sc_num_fan; i++) { 77102222f5cSkettenis if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) { 77202222f5cSkettenis sc->sc_fan[i].flags |= SENSOR_FINVALID; 77302222f5cSkettenis continue; 77402222f5cSkettenis } 77502222f5cSkettenis 77602222f5cSkettenis sc->sc_fan[i].value = (60 * sc->sc_fan_cal[i] * val) / 100; 777df54a7c0Skettenis if (val < sc->sc_fan_low[i]) 778df54a7c0Skettenis sc->sc_fan[i].status = SENSOR_S_CRIT; 779df54a7c0Skettenis else 780df54a7c0Skettenis sc->sc_fan[i].status = SENSOR_S_OK; 78102222f5cSkettenis sc->sc_fan[i].flags &= ~SENSOR_FINVALID; 78202222f5cSkettenis } 7836801a748Skettenis 78478eeb547Skettenis for (i = 0; i < sc->sc_num_psu; i++) { 78578eeb547Skettenis if (lom_read(sc, LOM_IDX_PSU1 + i, &val) || 78678eeb547Skettenis !ISSET(val, LOM_PSU_PRESENT)) { 78778eeb547Skettenis sc->sc_psu[i].flags |= SENSOR_FINVALID; 78878eeb547Skettenis continue; 78978eeb547Skettenis } 79078eeb547Skettenis 79178eeb547Skettenis if (val & LOM_PSU_STANDBY) { 79278eeb547Skettenis sc->sc_psu[i].value = 0; 79378eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_UNSPEC; 79478eeb547Skettenis } else { 79578eeb547Skettenis sc->sc_psu[i].value = 1; 79678eeb547Skettenis if (ISSET(val, LOM_PSU_INPUTA) && 79778eeb547Skettenis ISSET(val, LOM_PSU_INPUTB) && 79878eeb547Skettenis ISSET(val, LOM_PSU_OUTPUT)) 79978eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_OK; 80078eeb547Skettenis else 80178eeb547Skettenis sc->sc_psu[i].status = SENSOR_S_CRIT; 80278eeb547Skettenis } 80378eeb547Skettenis sc->sc_psu[i].flags &= ~SENSOR_FINVALID; 80478eeb547Skettenis } 80578eeb547Skettenis 80678eeb547Skettenis for (i = 0; i < sc->sc_num_temp; i++) { 80778eeb547Skettenis if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) { 80878eeb547Skettenis sc->sc_temp[i].flags |= SENSOR_FINVALID; 80978eeb547Skettenis continue; 81078eeb547Skettenis } 81178eeb547Skettenis 81278eeb547Skettenis sc->sc_temp[i].value = val * 1000000 + 273150000; 81378eeb547Skettenis sc->sc_temp[i].flags &= ~SENSOR_FINVALID; 81478eeb547Skettenis } 81578eeb547Skettenis 8166801a748Skettenis /* 8176801a748Skettenis * If our hostname is set and differs from what's stored in 8186801a748Skettenis * the LOM, write the new hostname back to the LOM. Note that 8196801a748Skettenis * we include the terminating NUL when writing the hostname 820fc69c4e1Skettenis * back to the LOM, otherwise the LOM will print any trailing 8216801a748Skettenis * garbage. 8226801a748Skettenis */ 8236801a748Skettenis if (hostnamelen > 0 && 8246801a748Skettenis strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) { 82513d051d6Skettenis if (sc->sc_type < LOM_LOMLITE2) 82613d051d6Skettenis lom1_write_hostname(sc); 82713d051d6Skettenis else 82813d051d6Skettenis lom2_write_hostname(sc); 8296801a748Skettenis strlcpy(sc->sc_hostname, hostname, sizeof(hostname)); 8306801a748Skettenis } 8312613757eSkettenis } 832877407b4Skettenis 833877407b4Skettenis void 83413d051d6Skettenis lom1_write_hostname(struct lom_softc *sc) 83513d051d6Skettenis { 83613d051d6Skettenis char name[LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1]; 83713d051d6Skettenis char *p; 83813d051d6Skettenis int i; 83913d051d6Skettenis 84013d051d6Skettenis /* 84113d051d6Skettenis * LOMlite generally doesn't have enough space to store the 84213d051d6Skettenis * fully qualified hostname. If the hostname is too long, 84313d051d6Skettenis * strip off the domain name. 84413d051d6Skettenis */ 84513d051d6Skettenis strlcpy(name, hostname, sizeof(name)); 84613d051d6Skettenis if (hostnamelen > sizeof(name)) { 84713d051d6Skettenis p = strchr(name, '.'); 84813d051d6Skettenis if (p) 84913d051d6Skettenis *p = '\0'; 85013d051d6Skettenis } 85113d051d6Skettenis 85213d051d6Skettenis for (i = 0; i < strlen(name) + 1; i++) 8535e80de5eSkettenis if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i])) 8545e80de5eSkettenis break; 85513d051d6Skettenis } 85613d051d6Skettenis 85713d051d6Skettenis void 85813d051d6Skettenis lom2_write_hostname(struct lom_softc *sc) 85913d051d6Skettenis { 86013d051d6Skettenis int i; 86113d051d6Skettenis 86213d051d6Skettenis lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1); 86313d051d6Skettenis for (i = 0; i < hostnamelen + 1; i++) 86413d051d6Skettenis lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]); 86513d051d6Skettenis } 86613d051d6Skettenis 86713d051d6Skettenis void 868877407b4Skettenis lom_wdog_pat(void *arg) 869877407b4Skettenis { 870877407b4Skettenis struct lom_softc *sc; 871877407b4Skettenis 872877407b4Skettenis /* Pat the dog. */ 8735e80de5eSkettenis sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 8745e80de5eSkettenis sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 8755e80de5eSkettenis lom_queue_cmd(sc, &sc->sc_wdog_pat); 876877407b4Skettenis 877877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 878877407b4Skettenis } 879877407b4Skettenis 880877407b4Skettenis int 881877407b4Skettenis lom_wdog_cb(void *arg, int period) 882877407b4Skettenis { 883877407b4Skettenis struct lom_softc *sc = arg; 884877407b4Skettenis 885fc69c4e1Skettenis if (period > LOM_WDOG_TIME_MAX) 886fc69c4e1Skettenis period = LOM_WDOG_TIME_MAX; 887877407b4Skettenis else if (period < 0) 888877407b4Skettenis period = 0; 889877407b4Skettenis 890877407b4Skettenis if (period == 0) { 891877407b4Skettenis if (sc->sc_wdog_period != 0) { 892877407b4Skettenis /* Stop watchdog from resetting the machine. */ 8935223c73eSkettenis sc->sc_wdog_ctl &= ~LOM_WDOG_RESET; 8945223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 895877407b4Skettenis 896877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 897877407b4Skettenis timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 898877407b4Skettenis } 899877407b4Skettenis } else { 900877407b4Skettenis if (sc->sc_wdog_period != period) { 901877407b4Skettenis /* Set new timeout. */ 902877407b4Skettenis lom_write(sc, LOM_IDX_WDOG_TIME, period); 903877407b4Skettenis } 904877407b4Skettenis if (sc->sc_wdog_period == 0) { 905877407b4Skettenis /* Make watchdog reset the machine. */ 9065223c73eSkettenis sc->sc_wdog_ctl |= LOM_WDOG_RESET; 9075223c73eSkettenis lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 908877407b4Skettenis 909877407b4Skettenis timeout_del(&sc->sc_wdog_to); 910877407b4Skettenis } else { 911877407b4Skettenis /* Pat the dog. */ 912*a4f1f624Skettenis lom_dequeue_cmd(sc, &sc->sc_wdog_pat); 9135e80de5eSkettenis sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 9145e80de5eSkettenis sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 9155e80de5eSkettenis lom_queue_cmd(sc, &sc->sc_wdog_pat); 916877407b4Skettenis } 917877407b4Skettenis } 918877407b4Skettenis sc->sc_wdog_period = period; 919877407b4Skettenis 920877407b4Skettenis return (period); 921877407b4Skettenis } 922