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 != 0x55 || 2622613757eSkettenis lom_read(sc, LOM_IDX_PROBEAA, ®) || 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