1/* $NetBSD: lom.c,v 1.16 2018/09/03 16:29:27 riastradh Exp $ */ 2/* $OpenBSD: lom.c,v 1.21 2010/02/28 20:44:39 kettenis Exp $ */ 3/* 4 * Copyright (c) 2009 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/cdefs.h> 20__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.16 2018/09/03 16:29:27 riastradh Exp $"); 21 22#include <sys/param.h> 23#include <sys/device.h> 24#include <sys/kernel.h> 25#include <sys/proc.h> 26#include <sys/envsys.h> 27#include <sys/systm.h> 28#include <sys/callout.h> 29#include <sys/sysctl.h> 30 31#include <machine/autoconf.h> 32 33#include <dev/ebus/ebusreg.h> 34#include <dev/ebus/ebusvar.h> 35#include <dev/sysmon/sysmonvar.h> 36 37/* 38 * LOMlite is a so far unidentified microcontroller. 39 */ 40#define LOM1_STATUS 0x00 /* R */ 41#define LOM1_STATUS_BUSY 0x80 42#define LOM1_CMD 0x00 /* W */ 43#define LOM1_DATA 0x01 /* R/W */ 44 45/* 46 * LOMlite2 is implemented as a H8/3437 microcontroller which has its 47 * on-chip host interface hooked up to EBus. 48 */ 49#define LOM2_DATA 0x00 /* R/W */ 50#define LOM2_CMD 0x01 /* W */ 51#define LOM2_STATUS 0x01 /* R */ 52#define LOM2_STATUS_OBF 0x01 /* Output Buffer Full */ 53#define LOM2_STATUS_IBF 0x02 /* Input Buffer Full */ 54 55#define LOM_IDX_CMD 0x00 56#define LOM_IDX_CMD_GENERIC 0x00 57#define LOM_IDX_CMD_TEMP 0x04 58#define LOM_IDX_CMD_FAN 0x05 59 60#define LOM_IDX_FW_REV 0x01 /* Firmware revision */ 61 62#define LOM_IDX_FAN1 0x04 /* Fan speed */ 63#define LOM_IDX_FAN2 0x05 64#define LOM_IDX_FAN3 0x06 65#define LOM_IDX_FAN4 0x07 66#define LOM_IDX_PSU1 0x08 /* PSU status */ 67#define LOM_IDX_PSU2 0x09 68#define LOM_IDX_PSU3 0x0a 69#define LOM_PSU_INPUTA 0x01 70#define LOM_PSU_INPUTB 0x02 71#define LOM_PSU_OUTPUT 0x04 72#define LOM_PSU_PRESENT 0x08 73#define LOM_PSU_STANDBY 0x10 74 75#define LOM_IDX_TEMP1 0x18 /* Temperature */ 76#define LOM_IDX_TEMP2 0x19 77#define LOM_IDX_TEMP3 0x1a 78#define LOM_IDX_TEMP4 0x1b 79#define LOM_IDX_TEMP5 0x1c 80#define LOM_IDX_TEMP6 0x1d 81#define LOM_IDX_TEMP7 0x1e 82#define LOM_IDX_TEMP8 0x1f 83 84#define LOM_IDX_LED1 0x25 85 86#define LOM_IDX_ALARM 0x30 87#define LOM_ALARM_1 0x01 88#define LOM_ALARM_2 0x02 89#define LOM_ALARM_3 0x04 90#define LOM_ALARM_FAULT 0xf0 91#define LOM_IDX_WDOG_CTL 0x31 92#define LOM_WDOG_ENABLE 0x01 93#define LOM_WDOG_RESET 0x02 94#define LOM_WDOG_AL3_WDOG 0x04 95#define LOM_WDOG_AL3_FANPSU 0x08 96#define LOM_IDX_WDOG_TIME 0x32 97#define LOM_WDOG_TIME_MAX 126 98 99#define LOM1_IDX_HOSTNAME1 0x33 100#define LOM1_IDX_HOSTNAME2 0x34 101#define LOM1_IDX_HOSTNAME3 0x35 102#define LOM1_IDX_HOSTNAME4 0x36 103#define LOM1_IDX_HOSTNAME5 0x37 104#define LOM1_IDX_HOSTNAME6 0x38 105#define LOM1_IDX_HOSTNAME7 0x39 106#define LOM1_IDX_HOSTNAME8 0x3a 107#define LOM1_IDX_HOSTNAME9 0x3b 108#define LOM1_IDX_HOSTNAME10 0x3c 109#define LOM1_IDX_HOSTNAME11 0x3d 110#define LOM1_IDX_HOSTNAME12 0x3e 111 112#define LOM2_IDX_HOSTNAMELEN 0x38 113#define LOM2_IDX_HOSTNAME 0x39 114 115#define LOM_IDX_CONFIG 0x5d 116#define LOM_IDX_FAN1_CAL 0x5e 117#define LOM_IDX_FAN2_CAL 0x5f 118#define LOM_IDX_FAN3_CAL 0x60 119#define LOM_IDX_FAN4_CAL 0x61 120#define LOM_IDX_FAN1_LOW 0x62 121#define LOM_IDX_FAN2_LOW 0x63 122#define LOM_IDX_FAN3_LOW 0x64 123#define LOM_IDX_FAN4_LOW 0x65 124 125#define LOM_IDX_CONFIG2 0x66 126#define LOM_IDX_CONFIG3 0x67 127 128#define LOM_IDX_PROBE55 0x7e /* Always returns 0x55 */ 129#define LOM_IDX_PROBEAA 0x7f /* Always returns 0xaa */ 130 131#define LOM_IDX_WRITE 0x80 132 133#define LOM_IDX4_TEMP_NAME_START 0x40 134#define LOM_IDX4_TEMP_NAME_END 0xff 135 136#define LOM_IDX5_FAN_NAME_START 0x40 137#define LOM_IDX5_FAN_NAME_END 0xff 138 139#define LOM_MAX_ALARM 4 140#define LOM_MAX_FAN 4 141#define LOM_MAX_PSU 3 142#define LOM_MAX_TEMP 8 143 144struct lom_cmd { 145 uint8_t lc_cmd; 146 uint8_t lc_data; 147 148 TAILQ_ENTRY(lom_cmd) lc_next; 149}; 150 151struct lom_softc { 152 device_t sc_dev; 153 bus_space_tag_t sc_iot; 154 bus_space_handle_t sc_ioh; 155 156 int sc_type; 157#define LOM_LOMLITE 0 158#define LOM_LOMLITE2 2 159 int sc_space; 160 161 struct sysmon_envsys *sc_sme; 162 envsys_data_t sc_alarm[LOM_MAX_ALARM]; 163 envsys_data_t sc_fan[LOM_MAX_FAN]; 164 envsys_data_t sc_psu[LOM_MAX_PSU]; 165 envsys_data_t sc_temp[LOM_MAX_TEMP]; 166 167 int sc_num_alarm; 168 int sc_num_fan; 169 int sc_num_psu; 170 int sc_num_temp; 171 172 int32_t sc_sysctl_num[LOM_MAX_ALARM]; 173 174 struct timeval sc_alarm_lastread; 175 uint8_t sc_alarm_lastval; 176 struct timeval sc_fan_lastread[LOM_MAX_FAN]; 177 struct timeval sc_psu_lastread[LOM_MAX_PSU]; 178 struct timeval sc_temp_lastread[LOM_MAX_TEMP]; 179 180 uint8_t sc_fan_cal[LOM_MAX_FAN]; 181 uint8_t sc_fan_low[LOM_MAX_FAN]; 182 183 char sc_hostname[MAXHOSTNAMELEN]; 184 185 struct sysmon_wdog sc_smw; 186 int sc_wdog_period; 187 uint8_t sc_wdog_ctl; 188 struct lom_cmd sc_wdog_pat; 189 190 TAILQ_HEAD(, lom_cmd) sc_queue; 191 kmutex_t sc_queue_mtx; 192 struct callout sc_state_to; 193 int sc_state; 194#define LOM_STATE_IDLE 0 195#define LOM_STATE_CMD 1 196#define LOM_STATE_DATA 2 197 int sc_retry; 198}; 199 200static int lom_match(device_t, cfdata_t, void *); 201static void lom_attach(device_t, device_t, void *); 202 203CFATTACH_DECL_NEW(lom, sizeof(struct lom_softc), 204 lom_match, lom_attach, NULL, NULL); 205 206static int lom_read(struct lom_softc *, uint8_t, uint8_t *); 207static int lom_write(struct lom_softc *, uint8_t, uint8_t); 208static void lom_queue_cmd(struct lom_softc *, struct lom_cmd *); 209static void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *); 210static int lom1_read(struct lom_softc *, uint8_t, uint8_t *); 211static int lom1_write(struct lom_softc *, uint8_t, uint8_t); 212static int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *); 213static int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t); 214static void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *); 215static void lom1_process_queue(void *); 216static void lom1_process_queue_locked(struct lom_softc *); 217static int lom2_read(struct lom_softc *, uint8_t, uint8_t *); 218static int lom2_write(struct lom_softc *, uint8_t, uint8_t); 219static int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *); 220static int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t); 221static void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *); 222static int lom2_intr(void *); 223 224static int lom_init_desc(struct lom_softc *); 225static void lom_refresh(struct sysmon_envsys *, envsys_data_t *); 226static void lom_refresh_alarm(struct lom_softc *, envsys_data_t *, uint32_t); 227static void lom_refresh_fan(struct lom_softc *, envsys_data_t *, uint32_t); 228static void lom_refresh_psu(struct lom_softc *, envsys_data_t *, uint32_t); 229static void lom_refresh_temp(struct lom_softc *, envsys_data_t *, uint32_t); 230static void lom1_write_hostname(struct lom_softc *); 231static void lom2_write_hostname(struct lom_softc *); 232 233static int lom_wdog_tickle(struct sysmon_wdog *); 234static int lom_wdog_setmode(struct sysmon_wdog *); 235 236static bool lom_shutdown(device_t, int); 237 238SYSCTL_SETUP_PROTO(sysctl_lom_setup); 239static int lom_sysctl_alarm(SYSCTLFN_PROTO); 240 241static const char *nodename[LOM_MAX_ALARM] = 242 { "fault_led", "alarm1", "alarm2", "alarm3" }; 243#ifdef SYSCTL_INCLUDE_DESCR 244static const char *nodedesc[LOM_MAX_ALARM] = 245 { "Fault LED status", "Alarm1 status", "Alarm2 status ", "Alarm3 status" }; 246#endif 247static const struct timeval refresh_interval = { 1, 0 }; 248 249static int 250lom_match(device_t parent, cfdata_t match, void *aux) 251{ 252 struct ebus_attach_args *ea = aux; 253 254 if (strcmp(ea->ea_name, "SUNW,lom") == 0 || 255 strcmp(ea->ea_name, "SUNW,lomh") == 0) 256 return (1); 257 258 return (0); 259} 260 261static void 262lom_attach(device_t parent, device_t self, void *aux) 263{ 264 struct lom_softc *sc = device_private(self); 265 struct ebus_attach_args *ea = aux; 266 uint8_t reg, fw_rev, config, config2, config3; 267 uint8_t cal, low; 268 int i, err; 269 const struct sysctlnode *node = NULL, *newnode; 270 271 if (strcmp(ea->ea_name, "SUNW,lomh") == 0) { 272 if (ea->ea_nintr < 1) { 273 aprint_error(": no interrupt\n"); 274 return; 275 } 276 sc->sc_type = LOM_LOMLITE2; 277 } 278 279 sc->sc_dev = self; 280 sc->sc_iot = ea->ea_bustag; 281 if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 282 ea->ea_reg[0].size, 0, &sc->sc_ioh) != 0) { 283 aprint_error(": can't map register space\n"); 284 return; 285 } 286 287 if (sc->sc_type < LOM_LOMLITE2) { 288 /* XXX Magic */ 289 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0); 290 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca); 291 } 292 293 if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 || 294 lom_read(sc, LOM_IDX_PROBEAA, ®) || reg != 0xaa || 295 lom_read(sc, LOM_IDX_FW_REV, &fw_rev) || 296 lom_read(sc, LOM_IDX_CONFIG, &config)) 297 { 298 aprint_error(": not responding\n"); 299 return; 300 } 301 302 aprint_normal(": %s: %s rev %d.%d\n", ea->ea_name, 303 sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2", 304 fw_rev >> 4, fw_rev & 0x0f); 305 306 TAILQ_INIT(&sc->sc_queue); 307 mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_BIO); 308 309 config2 = config3 = 0; 310 if (sc->sc_type < LOM_LOMLITE2) { 311 /* 312 * LOMlite doesn't do interrupts so we limp along on 313 * timeouts. 314 */ 315 callout_init(&sc->sc_state_to, 0); 316 callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc); 317 } else { 318 lom_read(sc, LOM_IDX_CONFIG2, &config2); 319 lom_read(sc, LOM_IDX_CONFIG3, &config3); 320 321 bus_intr_establish(sc->sc_iot, ea->ea_intr[0], 322 IPL_BIO, lom2_intr, sc); 323 } 324 325 sc->sc_num_alarm = LOM_MAX_ALARM; 326 sc->sc_num_fan = uimin((config >> 5) & 0x7, LOM_MAX_FAN); 327 sc->sc_num_psu = uimin((config >> 3) & 0x3, LOM_MAX_PSU); 328 sc->sc_num_temp = uimin((config2 >> 4) & 0xf, LOM_MAX_TEMP); 329 330 aprint_verbose_dev(self, "%d fan(s), %d PSU(s), %d temp sensor(s)\n", 331 sc->sc_num_fan, sc->sc_num_psu, sc->sc_num_temp); 332 333 for (i = 0; i < sc->sc_num_fan; i++) { 334 if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) || 335 lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) { 336 aprint_error_dev(self, "can't read fan information\n"); 337 return; 338 } 339 sc->sc_fan_cal[i] = cal; 340 sc->sc_fan_low[i] = low; 341 } 342 343 /* Setup our sysctl subtree, hw.lomN */ 344 sysctl_createv(NULL, 0, NULL, &node, 345 0, CTLTYPE_NODE, device_xname(self), NULL, 346 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 347 348 /* Initialize sensor data. */ 349 sc->sc_sme = sysmon_envsys_create(); 350 for (i = 0; i < sc->sc_num_alarm; i++) { 351 sc->sc_alarm[i].units = ENVSYS_INDICATOR; 352 sc->sc_alarm[i].state = ENVSYS_SINVALID; 353 if (i == 0) 354 strlcpy(sc->sc_alarm[i].desc, "Fault LED", 355 sizeof(sc->sc_alarm[i].desc)); 356 else 357 snprintf(sc->sc_alarm[i].desc, 358 sizeof(sc->sc_alarm[i].desc), "Alarm%d", i); 359 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_alarm[i])) { 360 sysmon_envsys_destroy(sc->sc_sme); 361 aprint_error_dev(self, "can't attach alarm sensor\n"); 362 return; 363 } 364 if (node != NULL) { 365 sysctl_createv(NULL, 0, NULL, &newnode, 366 CTLFLAG_READWRITE, CTLTYPE_INT, nodename[i], 367 SYSCTL_DESCR(nodedesc[i]), 368 lom_sysctl_alarm, 0, (void *)sc, 0, 369 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); 370 if (newnode != NULL) 371 sc->sc_sysctl_num[i] = newnode->sysctl_num; 372 else 373 sc->sc_sysctl_num[i] = 0; 374 } 375 } 376 for (i = 0; i < sc->sc_num_fan; i++) { 377 sc->sc_fan[i].units = ENVSYS_SFANRPM; 378 sc->sc_fan[i].state = ENVSYS_SINVALID; 379 snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc), 380 "fan%d", i + 1); 381 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan[i])) { 382 sysmon_envsys_destroy(sc->sc_sme); 383 aprint_error_dev(self, "can't attach fan sensor\n"); 384 return; 385 } 386 } 387 for (i = 0; i < sc->sc_num_psu; i++) { 388 sc->sc_psu[i].units = ENVSYS_INDICATOR; 389 sc->sc_psu[i].state = ENVSYS_SINVALID; 390 snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc), 391 "PSU%d", i + 1); 392 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_psu[i])) { 393 sysmon_envsys_destroy(sc->sc_sme); 394 aprint_error_dev(self, "can't attach PSU sensor\n"); 395 return; 396 } 397 } 398 for (i = 0; i < sc->sc_num_temp; i++) { 399 sc->sc_temp[i].units = ENVSYS_STEMP; 400 sc->sc_temp[i].state = ENVSYS_SINVALID; 401 snprintf(sc->sc_temp[i].desc, sizeof(sc->sc_temp[i].desc), 402 "temp%d", i + 1); 403 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp[i])) { 404 sysmon_envsys_destroy(sc->sc_sme); 405 aprint_error_dev(self, "can't attach temp sensor\n"); 406 return; 407 } 408 } 409 if (lom_init_desc(sc)) { 410 aprint_error_dev(self, "can't read sensor names\n"); 411 sysmon_envsys_destroy(sc->sc_sme); 412 return; 413 } 414 415 sc->sc_sme->sme_name = device_xname(self); 416 sc->sc_sme->sme_cookie = sc; 417 sc->sc_sme->sme_refresh = lom_refresh; 418 err = sysmon_envsys_register(sc->sc_sme); 419 if (err) { 420 aprint_error_dev(self, 421 "unable to register envsys with sysmon, error %d\n", err); 422 sysmon_envsys_destroy(sc->sc_sme); 423 return; 424 } 425 426 /* Initialize watchdog. */ 427 lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 428 lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl); 429 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET); 430 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 431 432 sc->sc_wdog_period = LOM_WDOG_TIME_MAX; 433 434 sc->sc_smw.smw_name = device_xname(self); 435 sc->sc_smw.smw_cookie = sc; 436 sc->sc_smw.smw_setmode = lom_wdog_setmode; 437 sc->sc_smw.smw_tickle = lom_wdog_tickle; 438 sc->sc_smw.smw_period = sc->sc_wdog_period; 439 if (sysmon_wdog_register(&sc->sc_smw)) { 440 aprint_error_dev(self, 441 "unable to register wdog with sysmon\n"); 442 return; 443 } 444 445 aprint_verbose_dev(self, "Watchdog timer configured.\n"); 446 447 if (!pmf_device_register1(self, NULL, NULL, lom_shutdown)) 448 aprint_error_dev(self, "unable to register power handler\n"); 449} 450 451static int 452lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 453{ 454 if (sc->sc_type < LOM_LOMLITE2) 455 return lom1_read(sc, reg, val); 456 else 457 return lom2_read(sc, reg, val); 458} 459 460static int 461lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 462{ 463 if (sc->sc_type < LOM_LOMLITE2) 464 return lom1_write(sc, reg, val); 465 else 466 return lom2_write(sc, reg, val); 467} 468 469static void 470lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 471{ 472 if (sc->sc_type < LOM_LOMLITE2) 473 return lom1_queue_cmd(sc, lc); 474 else 475 return lom2_queue_cmd(sc, lc); 476} 477 478static void 479lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 480{ 481 struct lom_cmd *lcp; 482 483 mutex_enter(&sc->sc_queue_mtx); 484 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 485 if (lcp == lc) { 486 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 487 break; 488 } 489 } 490 mutex_exit(&sc->sc_queue_mtx); 491} 492 493static int 494lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 495{ 496 struct lom_cmd lc; 497 int error; 498 499 if (cold) 500 return lom1_read_polled(sc, reg, val); 501 502 lc.lc_cmd = reg; 503 lc.lc_data = 0xff; 504 lom1_queue_cmd(sc, &lc); 505 506 error = tsleep(&lc, PZERO, "lomrd", hz); 507 if (error) 508 lom_dequeue_cmd(sc, &lc); 509 510 *val = lc.lc_data; 511 512 return (error); 513} 514 515static int 516lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 517{ 518 struct lom_cmd lc; 519 int error; 520 521 if (cold) 522 return lom1_write_polled(sc, reg, val); 523 524 lc.lc_cmd = reg | LOM_IDX_WRITE; 525 lc.lc_data = val; 526 lom1_queue_cmd(sc, &lc); 527 528 error = tsleep(&lc, PZERO, "lomwr", 2 * hz); 529 if (error) 530 lom_dequeue_cmd(sc, &lc); 531 532 return (error); 533} 534 535static int 536lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 537{ 538 uint8_t str; 539 int i; 540 541 /* Wait for input buffer to become available. */ 542 for (i = 30; i > 0; i--) { 543 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 544 delay(1000); 545 if ((str & LOM1_STATUS_BUSY) == 0) 546 break; 547 } 548 if (i == 0) 549 return (ETIMEDOUT); 550 551 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 552 553 /* Wait until the microcontroller fills output buffer. */ 554 for (i = 30; i > 0; i--) { 555 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 556 delay(1000); 557 if ((str & LOM1_STATUS_BUSY) == 0) 558 break; 559 } 560 if (i == 0) 561 return (ETIMEDOUT); 562 563 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 564 return (0); 565} 566 567static int 568lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 569{ 570 uint8_t str; 571 int i; 572 573 /* Wait for input buffer to become available. */ 574 for (i = 30; i > 0; i--) { 575 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 576 delay(1000); 577 if ((str & LOM1_STATUS_BUSY) == 0) 578 break; 579 } 580 if (i == 0) 581 return (ETIMEDOUT); 582 583 reg |= LOM_IDX_WRITE; 584 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 585 586 /* Wait until the microcontroller fills output buffer. */ 587 for (i = 30; i > 0; i--) { 588 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 589 delay(1000); 590 if ((str & LOM1_STATUS_BUSY) == 0) 591 break; 592 } 593 if (i == 0) 594 return (ETIMEDOUT); 595 596 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val); 597 598 return (0); 599} 600 601static void 602lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 603{ 604 struct lom_cmd *lcp; 605 606 mutex_enter(&sc->sc_queue_mtx); 607 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 608 if (lcp == lc) { 609 mutex_exit(&sc->sc_queue_mtx); 610 return; 611 } 612 } 613 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 614 if (sc->sc_state == LOM_STATE_IDLE) { 615 sc->sc_state = LOM_STATE_CMD; 616 lom1_process_queue_locked(sc); 617 } 618 mutex_exit(&sc->sc_queue_mtx); 619} 620 621static void 622lom1_process_queue(void *arg) 623{ 624 struct lom_softc *sc = arg; 625 626 mutex_enter(&sc->sc_queue_mtx); 627 lom1_process_queue_locked(sc); 628 mutex_exit(&sc->sc_queue_mtx); 629} 630 631static void 632lom1_process_queue_locked(struct lom_softc *sc) 633{ 634 struct lom_cmd *lc; 635 uint8_t str; 636 637 lc = TAILQ_FIRST(&sc->sc_queue); 638 if (lc == NULL) { 639 sc->sc_state = LOM_STATE_IDLE; 640 return; 641 } 642 643 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 644 if (str & LOM1_STATUS_BUSY) { 645 if (sc->sc_retry++ < 30) { 646 callout_schedule(&sc->sc_state_to, mstohz(1)); 647 return; 648 } 649 650 /* 651 * Looks like the microcontroller got wedged. Unwedge 652 * it by writing this magic value. Give it some time 653 * to recover. 654 */ 655 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac); 656 callout_schedule(&sc->sc_state_to, mstohz(1000)); 657 sc->sc_state = LOM_STATE_CMD; 658 return; 659 } 660 661 sc->sc_retry = 0; 662 663 if (sc->sc_state == LOM_STATE_CMD) { 664 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd); 665 sc->sc_state = LOM_STATE_DATA; 666 callout_schedule(&sc->sc_state_to, mstohz(250)); 667 return; 668 } 669 670 KASSERT(sc->sc_state == LOM_STATE_DATA); 671 if ((lc->lc_cmd & LOM_IDX_WRITE) == 0) 672 lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 673 else 674 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data); 675 676 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 677 678 wakeup(lc); 679 680 if (!TAILQ_EMPTY(&sc->sc_queue)) { 681 sc->sc_state = LOM_STATE_CMD; 682 callout_schedule(&sc->sc_state_to, mstohz(1)); 683 return; 684 } 685 686 sc->sc_state = LOM_STATE_IDLE; 687} 688 689static int 690lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 691{ 692 struct lom_cmd lc; 693 int error; 694 695 if (cold) 696 return lom2_read_polled(sc, reg, val); 697 698 lc.lc_cmd = reg; 699 lc.lc_data = 0xff; 700 lom2_queue_cmd(sc, &lc); 701 702 error = tsleep(&lc, PZERO, "lom2rd", hz); 703 if (error) 704 lom_dequeue_cmd(sc, &lc); 705 706 *val = lc.lc_data; 707 708 return (error); 709} 710 711static int 712lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 713{ 714 uint8_t str; 715 int i; 716 717 /* Wait for input buffer to become available. */ 718 for (i = 1000; i > 0; i--) { 719 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 720 delay(10); 721 if ((str & LOM2_STATUS_IBF) == 0) 722 break; 723 } 724 if (i == 0) 725 return (ETIMEDOUT); 726 727 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 728 729 /* Wait until the microcontroller fills output buffer. */ 730 for (i = 1000; i > 0; i--) { 731 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 732 delay(10); 733 if (str & LOM2_STATUS_OBF) 734 break; 735 } 736 if (i == 0) 737 return (ETIMEDOUT); 738 739 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 740 return (0); 741} 742 743static int 744lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 745{ 746 struct lom_cmd lc; 747 int error; 748 749 if (cold) 750 return lom2_write_polled(sc, reg, val); 751 752 lc.lc_cmd = reg | LOM_IDX_WRITE; 753 lc.lc_data = val; 754 lom2_queue_cmd(sc, &lc); 755 756 error = tsleep(&lc, PZERO, "lom2wr", hz); 757 if (error) 758 lom_dequeue_cmd(sc, &lc); 759 760 return (error); 761} 762 763static int 764lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 765{ 766 uint8_t str; 767 int i; 768 769 /* Wait for input buffer to become available. */ 770 for (i = 1000; i > 0; i--) { 771 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 772 delay(10); 773 if ((str & LOM2_STATUS_IBF) == 0) 774 break; 775 } 776 if (i == 0) 777 return (ETIMEDOUT); 778 779 if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD) 780 reg |= LOM_IDX_WRITE; 781 782 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 783 784 /* Wait until the microcontroller fills output buffer. */ 785 for (i = 1000; i > 0; i--) { 786 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 787 delay(10); 788 if (str & LOM2_STATUS_OBF) 789 break; 790 } 791 if (i == 0) 792 return (ETIMEDOUT); 793 794 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 795 796 /* Wait for input buffer to become available. */ 797 for (i = 1000; i > 0; i--) { 798 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 799 delay(10); 800 if ((str & LOM2_STATUS_IBF) == 0) 801 break; 802 } 803 if (i == 0) 804 return (ETIMEDOUT); 805 806 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val); 807 808 /* Wait until the microcontroller fills output buffer. */ 809 for (i = 1000; i > 0; i--) { 810 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 811 delay(10); 812 if (str & LOM2_STATUS_OBF) 813 break; 814 } 815 if (i == 0) 816 return (ETIMEDOUT); 817 818 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 819 820 /* If we switched spaces, remember the one we're in now. */ 821 if (reg == LOM_IDX_CMD) 822 sc->sc_space = val; 823 824 return (0); 825} 826 827static void 828lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 829{ 830 struct lom_cmd *lcp; 831 uint8_t str; 832 833 mutex_enter(&sc->sc_queue_mtx); 834 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 835 if (lcp == lc) { 836 mutex_exit(&sc->sc_queue_mtx); 837 return; 838 } 839 } 840 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 841 if (sc->sc_state == LOM_STATE_IDLE) { 842 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 843 if ((str & LOM2_STATUS_IBF) == 0) { 844 lc = TAILQ_FIRST(&sc->sc_queue); 845 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 846 LOM2_CMD, lc->lc_cmd); 847 sc->sc_state = LOM_STATE_DATA; 848 } 849 } 850 mutex_exit(&sc->sc_queue_mtx); 851} 852 853static int 854lom2_intr(void *arg) 855{ 856 struct lom_softc *sc = arg; 857 struct lom_cmd *lc; 858 uint8_t str, obr; 859 860 mutex_enter(&sc->sc_queue_mtx); 861 862 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 863 obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 864 865 lc = TAILQ_FIRST(&sc->sc_queue); 866 if (lc == NULL) { 867 mutex_exit(&sc->sc_queue_mtx); 868 return (0); 869 } 870 871 if (lc->lc_cmd & LOM_IDX_WRITE) { 872 if ((str & LOM2_STATUS_IBF) == 0) { 873 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 874 LOM2_DATA, lc->lc_data); 875 lc->lc_cmd &= ~LOM_IDX_WRITE; 876 } 877 mutex_exit(&sc->sc_queue_mtx); 878 return (1); 879 } 880 881 KASSERT(sc->sc_state == LOM_STATE_DATA); 882 lc->lc_data = obr; 883 884 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 885 886 wakeup(lc); 887 888 sc->sc_state = LOM_STATE_IDLE; 889 890 if (!TAILQ_EMPTY(&sc->sc_queue)) { 891 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 892 if ((str & LOM2_STATUS_IBF) == 0) { 893 lc = TAILQ_FIRST(&sc->sc_queue); 894 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 895 LOM2_CMD, lc->lc_cmd); 896 sc->sc_state = LOM_STATE_DATA; 897 } 898 } 899 900 mutex_exit(&sc->sc_queue_mtx); 901 902 return (1); 903} 904 905static int 906lom_init_desc(struct lom_softc *sc) 907{ 908 uint8_t val; 909 int i, j, k; 910 int error; 911 912 /* LOMlite doesn't provide sensor descriptions. */ 913 if (sc->sc_type < LOM_LOMLITE2) 914 return (0); 915 916 /* 917 * Read temperature sensor names. 918 */ 919 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP); 920 if (error) 921 return (error); 922 923 i = 0; 924 j = 0; 925 k = LOM_IDX4_TEMP_NAME_START; 926 while (k <= LOM_IDX4_TEMP_NAME_END) { 927 error = lom_read(sc, k++, &val); 928 if (error) 929 goto fail; 930 931 if (val == 0xff) 932 break; 933 934 if (j < sizeof (sc->sc_temp[i].desc) - 1) 935 sc->sc_temp[i].desc[j++] = val; 936 937 if (val == '\0') { 938 i++; 939 j = 0; 940 if (i < sc->sc_num_temp) 941 continue; 942 943 break; 944 } 945 } 946 947 /* 948 * Read fan names. 949 */ 950 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN); 951 if (error) 952 return (error); 953 954 i = 0; 955 j = 0; 956 k = LOM_IDX5_FAN_NAME_START; 957 while (k <= LOM_IDX5_FAN_NAME_END) { 958 error = lom_read(sc, k++, &val); 959 if (error) 960 goto fail; 961 962 if (val == 0xff) 963 break; 964 965 if (j < sizeof (sc->sc_fan[i].desc) - 1) 966 sc->sc_fan[i].desc[j++] = val; 967 968 if (val == '\0') { 969 i++; 970 j = 0; 971 if (i < sc->sc_num_fan) 972 continue; 973 974 break; 975 } 976 } 977 978fail: 979 lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC); 980 return (error); 981} 982 983static void 984lom_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 985{ 986 struct lom_softc *sc = sme->sme_cookie; 987 uint32_t i; 988 989 /* Sensor number */ 990 i = edata->sensor; 991 992 /* Sensor type */ 993 switch (edata->units) { 994 case ENVSYS_INDICATOR: 995 if (i < sc->sc_num_alarm) 996 lom_refresh_alarm(sc, edata, i); 997 else 998 lom_refresh_psu(sc, edata, 999 i - sc->sc_num_alarm - sc->sc_num_fan); 1000 break; 1001 case ENVSYS_SFANRPM: 1002 lom_refresh_fan(sc, edata, i - sc->sc_num_alarm); 1003 break; 1004 case ENVSYS_STEMP: 1005 lom_refresh_temp(sc, edata, 1006 i - sc->sc_num_alarm - sc->sc_num_fan - sc->sc_num_psu); 1007 break; 1008 default: 1009 edata->state = ENVSYS_SINVALID; 1010 break; 1011 } 1012 1013 /* 1014 * If our hostname is set and differs from what's stored in 1015 * the LOM, write the new hostname back to the LOM. Note that 1016 * we include the terminating NUL when writing the hostname 1017 * back to the LOM, otherwise the LOM will print any trailing 1018 * garbage. 1019 */ 1020 if (i == 0 && hostnamelen > 0 && 1021 strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) { 1022 if (sc->sc_type < LOM_LOMLITE2) 1023 lom1_write_hostname(sc); 1024 else 1025 lom2_write_hostname(sc); 1026 strlcpy(sc->sc_hostname, hostname, sizeof(hostname)); 1027 } 1028} 1029 1030static void 1031lom_refresh_alarm(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1032{ 1033 uint8_t val; 1034 1035 /* Fault LED or Alarms */ 1036 KASSERT(i < sc->sc_num_alarm); 1037 1038 /* Read new value at most once every second. */ 1039 if (ratecheck(&sc->sc_alarm_lastread, &refresh_interval)) { 1040 if (lom_read(sc, LOM_IDX_ALARM, &val)) { 1041 edata->state = ENVSYS_SINVALID; 1042 return; 1043 } 1044 sc->sc_alarm_lastval = val; 1045 } else { 1046 val = sc->sc_alarm_lastval; 1047 } 1048 1049 if (i == 0) { 1050 /* Fault LED */ 1051 if ((val & LOM_ALARM_FAULT) == LOM_ALARM_FAULT) 1052 edata->value_cur = 0; 1053 else 1054 edata->value_cur = 1; 1055 } else { 1056 /* Alarms */ 1057 if ((val & (LOM_ALARM_1 << (i - 1))) == 0) 1058 edata->value_cur = 0; 1059 else 1060 edata->value_cur = 1; 1061 } 1062 edata->state = ENVSYS_SVALID; 1063} 1064 1065static void 1066lom_refresh_fan(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1067{ 1068 uint8_t val; 1069 1070 /* Fan speed */ 1071 KASSERT(i < sc->sc_num_fan); 1072 1073 /* Read new value at most once every second. */ 1074 if (!ratecheck(&sc->sc_fan_lastread[i], &refresh_interval)) 1075 return; 1076 1077 if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) { 1078 edata->state = ENVSYS_SINVALID; 1079 } else { 1080 edata->value_cur = (60 * sc->sc_fan_cal[i] * val) / 100; 1081 if (val < sc->sc_fan_low[i]) 1082 edata->state = ENVSYS_SCRITICAL; 1083 else 1084 edata->state = ENVSYS_SVALID; 1085 } 1086} 1087 1088static void 1089lom_refresh_psu(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1090{ 1091 uint8_t val; 1092 1093 /* PSU status */ 1094 KASSERT(i < sc->sc_num_psu); 1095 1096 /* Read new value at most once every second. */ 1097 if (!ratecheck(&sc->sc_psu_lastread[i], &refresh_interval)) 1098 return; 1099 1100 if (lom_read(sc, LOM_IDX_PSU1 + i, &val) || 1101 !ISSET(val, LOM_PSU_PRESENT)) { 1102 edata->state = ENVSYS_SINVALID; 1103 } else { 1104 if (val & LOM_PSU_STANDBY) { 1105 edata->value_cur = 0; 1106 edata->state = ENVSYS_SVALID; 1107 } else { 1108 edata->value_cur = 1; 1109 if (ISSET(val, LOM_PSU_INPUTA) && 1110 ISSET(val, LOM_PSU_INPUTB) && 1111 ISSET(val, LOM_PSU_OUTPUT)) 1112 edata->state = ENVSYS_SVALID; 1113 else 1114 edata->state = ENVSYS_SCRITICAL; 1115 } 1116 } 1117} 1118 1119static void 1120lom_refresh_temp(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1121{ 1122 uint8_t val; 1123 1124 /* Temperature */ 1125 KASSERT(i < sc->sc_num_temp); 1126 1127 /* Read new value at most once every second. */ 1128 if (!ratecheck(&sc->sc_temp_lastread[i], &refresh_interval)) 1129 return; 1130 1131 if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) { 1132 edata->state = ENVSYS_SINVALID; 1133 } else { 1134 edata->value_cur = val * 1000000 + 273150000; 1135 edata->state = ENVSYS_SVALID; 1136 } 1137} 1138 1139static void 1140lom1_write_hostname(struct lom_softc *sc) 1141{ 1142 char name[(LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1) + 1]; 1143 char *p; 1144 int i; 1145 1146 /* 1147 * LOMlite generally doesn't have enough space to store the 1148 * fully qualified hostname. If the hostname is too long, 1149 * strip off the domain name. 1150 */ 1151 strlcpy(name, hostname, sizeof(name)); 1152 if (hostnamelen >= sizeof(name)) { 1153 p = strchr(name, '.'); 1154 if (p) 1155 *p = '\0'; 1156 } 1157 1158 for (i = 0; i < strlen(name) + 1; i++) 1159 if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i])) 1160 break; 1161} 1162 1163static void 1164lom2_write_hostname(struct lom_softc *sc) 1165{ 1166 int i; 1167 1168 lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1); 1169 for (i = 0; i < hostnamelen + 1; i++) 1170 lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]); 1171} 1172 1173static int 1174lom_wdog_tickle(struct sysmon_wdog *smw) 1175{ 1176 struct lom_softc *sc = smw->smw_cookie; 1177 1178 /* Pat the dog. */ 1179 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 1180 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 1181 lom_queue_cmd(sc, &sc->sc_wdog_pat); 1182 1183 return 0; 1184} 1185 1186static int 1187lom_wdog_setmode(struct sysmon_wdog *smw) 1188{ 1189 struct lom_softc *sc = smw->smw_cookie; 1190 1191 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 1192 /* disable watchdog */ 1193 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET); 1194 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1195 } else { 1196 if (smw->smw_period == WDOG_PERIOD_DEFAULT) 1197 smw->smw_period = sc->sc_wdog_period; 1198 else if (smw->smw_period == 0 || 1199 smw->smw_period > LOM_WDOG_TIME_MAX) 1200 return EINVAL; 1201 lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period); 1202 1203 /* enable watchdog */ 1204 lom_dequeue_cmd(sc, &sc->sc_wdog_pat); 1205 sc->sc_wdog_ctl |= LOM_WDOG_ENABLE|LOM_WDOG_RESET; 1206 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 1207 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 1208 lom_queue_cmd(sc, &sc->sc_wdog_pat); 1209 } 1210 1211 return 0; 1212} 1213 1214static bool 1215lom_shutdown(device_t dev, int how) 1216{ 1217 struct lom_softc *sc = device_private(dev); 1218 1219 sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE; 1220 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1221 return true; 1222} 1223 1224static int 1225lom_sysctl_alarm(SYSCTLFN_ARGS) 1226{ 1227 struct sysctlnode node; 1228 struct lom_softc *sc; 1229 int i, tmp, error; 1230 uint8_t val; 1231 1232 node = *rnode; 1233 sc = node.sysctl_data; 1234 1235 for (i = 0; i < sc->sc_num_alarm; i++) { 1236 if (node.sysctl_num == sc->sc_sysctl_num[i]) { 1237 lom_refresh_alarm(sc, &sc->sc_alarm[i], i); 1238 tmp = sc->sc_alarm[i].value_cur; 1239 node.sysctl_data = &tmp; 1240 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1241 if (error || newp == NULL) 1242 return error; 1243 if (tmp < 0 || tmp > 1) 1244 return EINVAL; 1245 1246 if (lom_read(sc, LOM_IDX_ALARM, &val)) 1247 return EINVAL; 1248 if (i == 0) { 1249 /* Fault LED */ 1250 if (tmp != 0) 1251 val &= ~LOM_ALARM_FAULT; 1252 else 1253 val |= LOM_ALARM_FAULT; 1254 } else { 1255 /* Alarms */ 1256 if (tmp != 0) 1257 val |= LOM_ALARM_1 << (i - 1); 1258 else 1259 val &= ~(LOM_ALARM_1 << (i - 1)); 1260 } 1261 if (lom_write(sc, LOM_IDX_ALARM, val)) 1262 return EINVAL; 1263 1264 sc->sc_alarm[i].value_cur = tmp; 1265 return 0; 1266 } 1267 } 1268 1269 return ENOENT; 1270} 1271