1 /* $NetBSD: lom.c,v 1.9 2011/06/20 17:01:45 pgoyette 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.9 2011/06/20 17:01:45 pgoyette 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 144 struct lom_cmd { 145 uint8_t lc_cmd; 146 uint8_t lc_data; 147 148 TAILQ_ENTRY(lom_cmd) lc_next; 149 }; 150 151 struct 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 200 static int lom_match(device_t, cfdata_t, void *); 201 static void lom_attach(device_t, device_t, void *); 202 203 CFATTACH_DECL_NEW(lom, sizeof(struct lom_softc), 204 lom_match, lom_attach, NULL, NULL); 205 206 static int lom_read(struct lom_softc *, uint8_t, uint8_t *); 207 static int lom_write(struct lom_softc *, uint8_t, uint8_t); 208 static void lom_queue_cmd(struct lom_softc *, struct lom_cmd *); 209 static void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *); 210 static int lom1_read(struct lom_softc *, uint8_t, uint8_t *); 211 static int lom1_write(struct lom_softc *, uint8_t, uint8_t); 212 static int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *); 213 static int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t); 214 static void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *); 215 static void lom1_process_queue(void *); 216 static void lom1_process_queue_locked(struct lom_softc *); 217 static int lom2_read(struct lom_softc *, uint8_t, uint8_t *); 218 static int lom2_write(struct lom_softc *, uint8_t, uint8_t); 219 static int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *); 220 static int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t); 221 static void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *); 222 static int lom2_intr(void *); 223 224 static int lom_init_desc(struct lom_softc *); 225 static void lom_refresh(struct sysmon_envsys *, envsys_data_t *); 226 static void lom_refresh_alarm(struct lom_softc *, envsys_data_t *, uint32_t); 227 static void lom_refresh_fan(struct lom_softc *, envsys_data_t *, uint32_t); 228 static void lom_refresh_psu(struct lom_softc *, envsys_data_t *, uint32_t); 229 static void lom_refresh_temp(struct lom_softc *, envsys_data_t *, uint32_t); 230 static void lom1_write_hostname(struct lom_softc *); 231 static void lom2_write_hostname(struct lom_softc *); 232 233 static int lom_wdog_tickle(struct sysmon_wdog *); 234 static int lom_wdog_setmode(struct sysmon_wdog *); 235 236 static bool lom_shutdown(device_t, int); 237 238 SYSCTL_SETUP_PROTO(sysctl_lom_setup); 239 static int lom_sysctl_alarm(SYSCTLFN_PROTO); 240 241 static int hw_node = CTL_EOL; 242 static const char *nodename[LOM_MAX_ALARM] = 243 { "fault_led", "alarm1", "alarm2", "alarm3" }; 244 #ifdef SYSCTL_INCLUDE_DESCR 245 static const char *nodedesc[LOM_MAX_ALARM] = 246 { "Fault LED status", "Alarm1 status", "Alarm2 status ", "Alarm3 status" }; 247 #endif 248 static const struct timeval refresh_interval = { 1, 0 }; 249 250 static int 251 lom_match(device_t parent, cfdata_t match, void *aux) 252 { 253 struct ebus_attach_args *ea = aux; 254 255 if (strcmp(ea->ea_name, "SUNW,lom") == 0 || 256 strcmp(ea->ea_name, "SUNW,lomh") == 0) 257 return (1); 258 259 return (0); 260 } 261 262 static void 263 lom_attach(device_t parent, device_t self, void *aux) 264 { 265 struct lom_softc *sc = device_private(self); 266 struct ebus_attach_args *ea = aux; 267 uint8_t reg, fw_rev, config, config2, config3; 268 uint8_t cal, low; 269 int i; 270 const struct sysctlnode *node = NULL, *newnode; 271 272 if (strcmp(ea->ea_name, "SUNW,lomh") == 0) { 273 if (ea->ea_nintr < 1) { 274 aprint_error(": no interrupt\n"); 275 return; 276 } 277 sc->sc_type = LOM_LOMLITE2; 278 } 279 280 sc->sc_dev = self; 281 sc->sc_iot = ea->ea_bustag; 282 if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 283 ea->ea_reg[0].size, 0, &sc->sc_ioh) != 0) { 284 aprint_error(": can't map register space\n"); 285 return; 286 } 287 288 if (sc->sc_type < LOM_LOMLITE2) { 289 /* XXX Magic */ 290 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0); 291 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca); 292 } 293 294 if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 || 295 lom_read(sc, LOM_IDX_PROBEAA, ®) || reg != 0xaa || 296 lom_read(sc, LOM_IDX_FW_REV, &fw_rev) || 297 lom_read(sc, LOM_IDX_CONFIG, &config)) 298 { 299 aprint_error(": not responding\n"); 300 return; 301 } 302 303 aprint_normal(": %s: %s rev %d.%d\n", ea->ea_name, 304 sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2", 305 fw_rev >> 4, fw_rev & 0x0f); 306 307 TAILQ_INIT(&sc->sc_queue); 308 mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_BIO); 309 310 config2 = config3 = 0; 311 if (sc->sc_type < LOM_LOMLITE2) { 312 /* 313 * LOMlite doesn't do interrupts so we limp along on 314 * timeouts. 315 */ 316 callout_init(&sc->sc_state_to, 0); 317 callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc); 318 } else { 319 lom_read(sc, LOM_IDX_CONFIG2, &config2); 320 lom_read(sc, LOM_IDX_CONFIG3, &config3); 321 322 bus_intr_establish(sc->sc_iot, ea->ea_intr[0], 323 IPL_BIO, lom2_intr, sc); 324 } 325 326 sc->sc_num_alarm = LOM_MAX_ALARM; 327 sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN); 328 sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU); 329 sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP); 330 331 aprint_verbose_dev(self, "%d fan(s), %d PSU(s), %d temp sensor(s)\n", 332 sc->sc_num_fan, sc->sc_num_psu, sc->sc_num_temp); 333 334 for (i = 0; i < sc->sc_num_fan; i++) { 335 if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) || 336 lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) { 337 aprint_error_dev(self, "can't read fan information\n"); 338 return; 339 } 340 sc->sc_fan_cal[i] = cal; 341 sc->sc_fan_low[i] = low; 342 } 343 344 /* Setup our sysctl subtree, hw.lomN */ 345 if (hw_node != CTL_EOL) 346 sysctl_createv(NULL, 0, NULL, &node, 347 0, CTLTYPE_NODE, device_xname(self), NULL, 348 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 349 350 /* Initialize sensor data. */ 351 sc->sc_sme = sysmon_envsys_create(); 352 for (i = 0; i < sc->sc_num_alarm; i++) { 353 sc->sc_alarm[i].units = ENVSYS_INDICATOR; 354 sc->sc_alarm[i].state = ENVSYS_SINVALID; 355 snprintf(sc->sc_alarm[i].desc, sizeof(sc->sc_alarm[i].desc), 356 i == 0 ? "Fault LED" : "Alarm%d", i); 357 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_alarm[i])) { 358 sysmon_envsys_destroy(sc->sc_sme); 359 aprint_error_dev(self, "can't attach alarm sensor\n"); 360 return; 361 } 362 if (node != NULL) { 363 sysctl_createv(NULL, 0, NULL, &newnode, 364 CTLFLAG_READWRITE, CTLTYPE_INT, nodename[i], 365 SYSCTL_DESCR(nodedesc[i]), 366 lom_sysctl_alarm, 0, sc, 0, 367 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); 368 if (newnode != NULL) 369 sc->sc_sysctl_num[i] = newnode->sysctl_num; 370 else 371 sc->sc_sysctl_num[i] = 0; 372 } 373 } 374 for (i = 0; i < sc->sc_num_fan; i++) { 375 sc->sc_fan[i].units = ENVSYS_SFANRPM; 376 sc->sc_fan[i].state = ENVSYS_SINVALID; 377 snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc), 378 "fan%d", i + 1); 379 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan[i])) { 380 sysmon_envsys_destroy(sc->sc_sme); 381 aprint_error_dev(self, "can't attach fan sensor\n"); 382 return; 383 } 384 } 385 for (i = 0; i < sc->sc_num_psu; i++) { 386 sc->sc_psu[i].units = ENVSYS_INDICATOR; 387 sc->sc_psu[i].state = ENVSYS_SINVALID; 388 snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc), 389 "PSU%d", i + 1); 390 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_psu[i])) { 391 sysmon_envsys_destroy(sc->sc_sme); 392 aprint_error_dev(self, "can't attach PSU sensor\n"); 393 return; 394 } 395 } 396 for (i = 0; i < sc->sc_num_temp; i++) { 397 sc->sc_temp[i].units = ENVSYS_STEMP; 398 sc->sc_temp[i].state = ENVSYS_SINVALID; 399 snprintf(sc->sc_temp[i].desc, sizeof(sc->sc_temp[i].desc), 400 "temp%d", i + 1); 401 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp[i])) { 402 sysmon_envsys_destroy(sc->sc_sme); 403 aprint_error_dev(self, "can't attach temp sensor\n"); 404 return; 405 } 406 } 407 if (lom_init_desc(sc)) { 408 aprint_error_dev(self, "can't read sensor names\n"); 409 sysmon_envsys_destroy(sc->sc_sme); 410 return; 411 } 412 413 sc->sc_sme->sme_name = device_xname(self); 414 sc->sc_sme->sme_cookie = sc; 415 sc->sc_sme->sme_refresh = lom_refresh; 416 if (sysmon_envsys_register(sc->sc_sme)) { 417 aprint_error_dev(self, 418 "unable to register envsys with sysmon\n"); 419 sysmon_envsys_destroy(sc->sc_sme); 420 return; 421 } 422 423 /* Initialize watchdog. */ 424 lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 425 lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl); 426 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET); 427 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 428 429 sc->sc_wdog_period = LOM_WDOG_TIME_MAX; 430 431 sc->sc_smw.smw_name = device_xname(self); 432 sc->sc_smw.smw_cookie = sc; 433 sc->sc_smw.smw_setmode = lom_wdog_setmode; 434 sc->sc_smw.smw_tickle = lom_wdog_tickle; 435 sc->sc_smw.smw_period = sc->sc_wdog_period; 436 if (sysmon_wdog_register(&sc->sc_smw)) { 437 aprint_error_dev(self, 438 "unable to register wdog with sysmon\n"); 439 return; 440 } 441 442 aprint_verbose_dev(self, "Watchdog timer configured.\n"); 443 444 if (!pmf_device_register1(self, NULL, NULL, lom_shutdown)) 445 aprint_error_dev(self, "unable to register power handler\n"); 446 } 447 448 static int 449 lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 450 { 451 if (sc->sc_type < LOM_LOMLITE2) 452 return lom1_read(sc, reg, val); 453 else 454 return lom2_read(sc, reg, val); 455 } 456 457 static int 458 lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 459 { 460 if (sc->sc_type < LOM_LOMLITE2) 461 return lom1_write(sc, reg, val); 462 else 463 return lom2_write(sc, reg, val); 464 } 465 466 static void 467 lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 468 { 469 if (sc->sc_type < LOM_LOMLITE2) 470 return lom1_queue_cmd(sc, lc); 471 else 472 return lom2_queue_cmd(sc, lc); 473 } 474 475 static void 476 lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 477 { 478 struct lom_cmd *lcp; 479 480 mutex_enter(&sc->sc_queue_mtx); 481 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 482 if (lcp == lc) { 483 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 484 break; 485 } 486 } 487 mutex_exit(&sc->sc_queue_mtx); 488 } 489 490 static int 491 lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 492 { 493 struct lom_cmd lc; 494 int error; 495 496 if (cold) 497 return lom1_read_polled(sc, reg, val); 498 499 lc.lc_cmd = reg; 500 lc.lc_data = 0xff; 501 lom1_queue_cmd(sc, &lc); 502 503 error = tsleep(&lc, PZERO, "lomrd", hz); 504 if (error) 505 lom_dequeue_cmd(sc, &lc); 506 507 *val = lc.lc_data; 508 509 return (error); 510 } 511 512 static int 513 lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 514 { 515 struct lom_cmd lc; 516 int error; 517 518 if (cold) 519 return lom1_write_polled(sc, reg, val); 520 521 lc.lc_cmd = reg | LOM_IDX_WRITE; 522 lc.lc_data = val; 523 lom1_queue_cmd(sc, &lc); 524 525 error = tsleep(&lc, PZERO, "lomwr", 2 * hz); 526 if (error) 527 lom_dequeue_cmd(sc, &lc); 528 529 return (error); 530 } 531 532 static int 533 lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 534 { 535 uint8_t str; 536 int i; 537 538 /* Wait for input buffer to become available. */ 539 for (i = 30; i > 0; i--) { 540 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 541 delay(1000); 542 if ((str & LOM1_STATUS_BUSY) == 0) 543 break; 544 } 545 if (i == 0) 546 return (ETIMEDOUT); 547 548 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 549 550 /* Wait until the microcontroller fills output buffer. */ 551 for (i = 30; i > 0; i--) { 552 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 553 delay(1000); 554 if ((str & LOM1_STATUS_BUSY) == 0) 555 break; 556 } 557 if (i == 0) 558 return (ETIMEDOUT); 559 560 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 561 return (0); 562 } 563 564 static int 565 lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 566 { 567 uint8_t str; 568 int i; 569 570 /* Wait for input buffer to become available. */ 571 for (i = 30; i > 0; i--) { 572 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 573 delay(1000); 574 if ((str & LOM1_STATUS_BUSY) == 0) 575 break; 576 } 577 if (i == 0) 578 return (ETIMEDOUT); 579 580 reg |= LOM_IDX_WRITE; 581 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 582 583 /* Wait until the microcontroller fills output buffer. */ 584 for (i = 30; i > 0; i--) { 585 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 586 delay(1000); 587 if ((str & LOM1_STATUS_BUSY) == 0) 588 break; 589 } 590 if (i == 0) 591 return (ETIMEDOUT); 592 593 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val); 594 595 return (0); 596 } 597 598 static void 599 lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 600 { 601 mutex_enter(&sc->sc_queue_mtx); 602 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 603 if (sc->sc_state == LOM_STATE_IDLE) { 604 sc->sc_state = LOM_STATE_CMD; 605 lom1_process_queue_locked(sc); 606 } 607 mutex_exit(&sc->sc_queue_mtx); 608 } 609 610 static void 611 lom1_process_queue(void *arg) 612 { 613 struct lom_softc *sc = arg; 614 615 mutex_enter(&sc->sc_queue_mtx); 616 lom1_process_queue_locked(sc); 617 mutex_exit(&sc->sc_queue_mtx); 618 } 619 620 static void 621 lom1_process_queue_locked(struct lom_softc *sc) 622 { 623 struct lom_cmd *lc; 624 uint8_t str; 625 626 lc = TAILQ_FIRST(&sc->sc_queue); 627 if (lc == NULL) { 628 sc->sc_state = LOM_STATE_IDLE; 629 return; 630 } 631 632 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 633 if (str & LOM1_STATUS_BUSY) { 634 if (sc->sc_retry++ < 30) { 635 callout_schedule(&sc->sc_state_to, mstohz(1)); 636 return; 637 } 638 639 /* 640 * Looks like the microcontroller got wedged. Unwedge 641 * it by writing this magic value. Give it some time 642 * to recover. 643 */ 644 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac); 645 callout_schedule(&sc->sc_state_to, mstohz(1000)); 646 sc->sc_state = LOM_STATE_CMD; 647 return; 648 } 649 650 sc->sc_retry = 0; 651 652 if (sc->sc_state == LOM_STATE_CMD) { 653 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd); 654 sc->sc_state = LOM_STATE_DATA; 655 callout_schedule(&sc->sc_state_to, mstohz(250)); 656 return; 657 } 658 659 KASSERT(sc->sc_state == LOM_STATE_DATA); 660 if ((lc->lc_cmd & LOM_IDX_WRITE) == 0) 661 lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 662 else 663 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data); 664 665 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 666 667 wakeup(lc); 668 669 if (!TAILQ_EMPTY(&sc->sc_queue)) { 670 sc->sc_state = LOM_STATE_CMD; 671 callout_schedule(&sc->sc_state_to, mstohz(1)); 672 return; 673 } 674 675 sc->sc_state = LOM_STATE_IDLE; 676 } 677 678 static int 679 lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 680 { 681 struct lom_cmd lc; 682 int error; 683 684 if (cold) 685 return lom2_read_polled(sc, reg, val); 686 687 lc.lc_cmd = reg; 688 lc.lc_data = 0xff; 689 lom2_queue_cmd(sc, &lc); 690 691 error = tsleep(&lc, PZERO, "lom2rd", hz); 692 if (error) 693 lom_dequeue_cmd(sc, &lc); 694 695 *val = lc.lc_data; 696 697 return (error); 698 } 699 700 static int 701 lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 702 { 703 uint8_t str; 704 int i; 705 706 /* Wait for input buffer to become available. */ 707 for (i = 1000; i > 0; i--) { 708 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 709 delay(10); 710 if ((str & LOM2_STATUS_IBF) == 0) 711 break; 712 } 713 if (i == 0) 714 return (ETIMEDOUT); 715 716 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 717 718 /* Wait until the microcontroller fills output buffer. */ 719 for (i = 1000; i > 0; i--) { 720 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 721 delay(10); 722 if (str & LOM2_STATUS_OBF) 723 break; 724 } 725 if (i == 0) 726 return (ETIMEDOUT); 727 728 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 729 return (0); 730 } 731 732 static int 733 lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 734 { 735 struct lom_cmd lc; 736 int error; 737 738 if (cold) 739 return lom2_write_polled(sc, reg, val); 740 741 lc.lc_cmd = reg | LOM_IDX_WRITE; 742 lc.lc_data = val; 743 lom2_queue_cmd(sc, &lc); 744 745 error = tsleep(&lc, PZERO, "lom2wr", hz); 746 if (error) 747 lom_dequeue_cmd(sc, &lc); 748 749 return (error); 750 } 751 752 static int 753 lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 754 { 755 uint8_t str; 756 int i; 757 758 /* Wait for input buffer to become available. */ 759 for (i = 1000; i > 0; i--) { 760 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 761 delay(10); 762 if ((str & LOM2_STATUS_IBF) == 0) 763 break; 764 } 765 if (i == 0) 766 return (ETIMEDOUT); 767 768 if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD) 769 reg |= LOM_IDX_WRITE; 770 771 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 772 773 /* Wait until the microcontroller fills output buffer. */ 774 for (i = 1000; i > 0; i--) { 775 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 776 delay(10); 777 if (str & LOM2_STATUS_OBF) 778 break; 779 } 780 if (i == 0) 781 return (ETIMEDOUT); 782 783 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 784 785 /* Wait for input buffer to become available. */ 786 for (i = 1000; i > 0; i--) { 787 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 788 delay(10); 789 if ((str & LOM2_STATUS_IBF) == 0) 790 break; 791 } 792 if (i == 0) 793 return (ETIMEDOUT); 794 795 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val); 796 797 /* Wait until the microcontroller fills output buffer. */ 798 for (i = 1000; i > 0; i--) { 799 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 800 delay(10); 801 if (str & LOM2_STATUS_OBF) 802 break; 803 } 804 if (i == 0) 805 return (ETIMEDOUT); 806 807 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 808 809 /* If we switched spaces, remember the one we're in now. */ 810 if (reg == LOM_IDX_CMD) 811 sc->sc_space = val; 812 813 return (0); 814 } 815 816 static void 817 lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 818 { 819 uint8_t str; 820 821 mutex_enter(&sc->sc_queue_mtx); 822 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 823 if (sc->sc_state == LOM_STATE_IDLE) { 824 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 825 if ((str & LOM2_STATUS_IBF) == 0) { 826 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 827 LOM2_CMD, lc->lc_cmd); 828 sc->sc_state = LOM_STATE_DATA; 829 } 830 } 831 mutex_exit(&sc->sc_queue_mtx); 832 } 833 834 static int 835 lom2_intr(void *arg) 836 { 837 struct lom_softc *sc = arg; 838 struct lom_cmd *lc; 839 uint8_t str, obr; 840 841 mutex_enter(&sc->sc_queue_mtx); 842 843 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 844 obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 845 846 lc = TAILQ_FIRST(&sc->sc_queue); 847 if (lc == NULL) { 848 mutex_exit(&sc->sc_queue_mtx); 849 return (0); 850 } 851 852 if (lc->lc_cmd & LOM_IDX_WRITE) { 853 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 854 LOM2_DATA, lc->lc_data); 855 lc->lc_cmd &= ~LOM_IDX_WRITE; 856 mutex_exit(&sc->sc_queue_mtx); 857 return (1); 858 } 859 860 KASSERT(sc->sc_state = LOM_STATE_DATA); 861 lc->lc_data = obr; 862 863 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 864 865 wakeup(lc); 866 867 sc->sc_state = LOM_STATE_IDLE; 868 869 if (!TAILQ_EMPTY(&sc->sc_queue)) { 870 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 871 if ((str & LOM2_STATUS_IBF) == 0) { 872 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 873 LOM2_CMD, lc->lc_cmd); 874 sc->sc_state = LOM_STATE_DATA; 875 } 876 } 877 878 mutex_exit(&sc->sc_queue_mtx); 879 880 return (1); 881 } 882 883 static int 884 lom_init_desc(struct lom_softc *sc) 885 { 886 uint8_t val; 887 int i, j, k; 888 int error; 889 890 /* LOMlite doesn't provide sensor descriptions. */ 891 if (sc->sc_type < LOM_LOMLITE2) 892 return (0); 893 894 /* 895 * Read temperature sensor names. 896 */ 897 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP); 898 if (error) 899 return (error); 900 901 i = 0; 902 j = 0; 903 k = LOM_IDX4_TEMP_NAME_START; 904 while (k <= LOM_IDX4_TEMP_NAME_END) { 905 error = lom_read(sc, k++, &val); 906 if (error) 907 goto fail; 908 909 if (val == 0xff) 910 break; 911 912 if (j < sizeof (sc->sc_temp[i].desc) - 1) 913 sc->sc_temp[i].desc[j++] = val; 914 915 if (val == '\0') { 916 i++; 917 j = 0; 918 if (i < sc->sc_num_temp) 919 continue; 920 921 break; 922 } 923 } 924 925 /* 926 * Read fan names. 927 */ 928 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN); 929 if (error) 930 return (error); 931 932 i = 0; 933 j = 0; 934 k = LOM_IDX5_FAN_NAME_START; 935 while (k <= LOM_IDX5_FAN_NAME_END) { 936 error = lom_read(sc, k++, &val); 937 if (error) 938 goto fail; 939 940 if (val == 0xff) 941 break; 942 943 if (j < sizeof (sc->sc_fan[i].desc) - 1) 944 sc->sc_fan[i].desc[j++] = val; 945 946 if (val == '\0') { 947 i++; 948 j = 0; 949 if (i < sc->sc_num_fan) 950 continue; 951 952 break; 953 } 954 } 955 956 fail: 957 lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC); 958 return (error); 959 } 960 961 static void 962 lom_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 963 { 964 struct lom_softc *sc = sme->sme_cookie; 965 uint32_t i; 966 967 /* Sensor number */ 968 i = edata->sensor; 969 970 /* Sensor type */ 971 switch (edata->units) { 972 case ENVSYS_INDICATOR: 973 if (i < sc->sc_num_alarm) 974 lom_refresh_alarm(sc, edata, i); 975 else 976 lom_refresh_psu(sc, edata, 977 i - sc->sc_num_alarm - sc->sc_num_fan); 978 break; 979 case ENVSYS_SFANRPM: 980 lom_refresh_fan(sc, edata, i - sc->sc_num_alarm); 981 break; 982 case ENVSYS_STEMP: 983 lom_refresh_temp(sc, edata, 984 i - sc->sc_num_alarm - sc->sc_num_fan - sc->sc_num_psu); 985 break; 986 default: 987 edata->state = ENVSYS_SINVALID; 988 break; 989 } 990 991 /* 992 * If our hostname is set and differs from what's stored in 993 * the LOM, write the new hostname back to the LOM. Note that 994 * we include the terminating NUL when writing the hostname 995 * back to the LOM, otherwise the LOM will print any trailing 996 * garbage. 997 */ 998 if (i == 0 && hostnamelen > 0 && 999 strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) { 1000 if (sc->sc_type < LOM_LOMLITE2) 1001 lom1_write_hostname(sc); 1002 else 1003 lom2_write_hostname(sc); 1004 strlcpy(sc->sc_hostname, hostname, sizeof(hostname)); 1005 } 1006 } 1007 1008 static void 1009 lom_refresh_alarm(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1010 { 1011 uint8_t val; 1012 1013 /* Fault LED or Alarms */ 1014 KASSERT(i < sc->sc_num_alarm); 1015 1016 /* Read new value at most once every second. */ 1017 if (ratecheck(&sc->sc_alarm_lastread, &refresh_interval)) { 1018 if (lom_read(sc, LOM_IDX_ALARM, &val)) { 1019 edata->state = ENVSYS_SINVALID; 1020 return; 1021 } 1022 sc->sc_alarm_lastval = val; 1023 } else { 1024 val = sc->sc_alarm_lastval; 1025 } 1026 1027 if (i == 0) { 1028 /* Fault LED */ 1029 if ((val & LOM_ALARM_FAULT) == LOM_ALARM_FAULT) 1030 edata->value_cur = 0; 1031 else 1032 edata->value_cur = 1; 1033 } else { 1034 /* Alarms */ 1035 if ((val & (LOM_ALARM_1 << (i - 1))) == 0) 1036 edata->value_cur = 0; 1037 else 1038 edata->value_cur = 1; 1039 } 1040 edata->state = ENVSYS_SVALID; 1041 } 1042 1043 static void 1044 lom_refresh_fan(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1045 { 1046 uint8_t val; 1047 1048 /* Fan speed */ 1049 KASSERT(i < sc->sc_num_fan); 1050 1051 /* Read new value at most once every second. */ 1052 if (!ratecheck(&sc->sc_fan_lastread[i], &refresh_interval)) 1053 return; 1054 1055 if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) { 1056 edata->state = ENVSYS_SINVALID; 1057 } else { 1058 edata->value_cur = (60 * sc->sc_fan_cal[i] * val) / 100; 1059 if (val < sc->sc_fan_low[i]) 1060 edata->state = ENVSYS_SCRITICAL; 1061 else 1062 edata->state = ENVSYS_SVALID; 1063 } 1064 } 1065 1066 static void 1067 lom_refresh_psu(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1068 { 1069 uint8_t val; 1070 1071 /* PSU status */ 1072 KASSERT(i < sc->sc_num_psu); 1073 1074 /* Read new value at most once every second. */ 1075 if (!ratecheck(&sc->sc_psu_lastread[i], &refresh_interval)) 1076 return; 1077 1078 if (lom_read(sc, LOM_IDX_PSU1 + i, &val) || 1079 !ISSET(val, LOM_PSU_PRESENT)) { 1080 edata->state = ENVSYS_SINVALID; 1081 } else { 1082 if (val & LOM_PSU_STANDBY) { 1083 edata->value_cur = 0; 1084 edata->state = ENVSYS_SVALID; 1085 } else { 1086 edata->value_cur = 1; 1087 if (ISSET(val, LOM_PSU_INPUTA) && 1088 ISSET(val, LOM_PSU_INPUTB) && 1089 ISSET(val, LOM_PSU_OUTPUT)) 1090 edata->state = ENVSYS_SVALID; 1091 else 1092 edata->state = ENVSYS_SCRITICAL; 1093 } 1094 } 1095 } 1096 1097 static void 1098 lom_refresh_temp(struct lom_softc *sc, envsys_data_t *edata, uint32_t i) 1099 { 1100 uint8_t val; 1101 1102 /* Temperature */ 1103 KASSERT(i < sc->sc_num_temp); 1104 1105 /* Read new value at most once every second. */ 1106 if (!ratecheck(&sc->sc_temp_lastread[i], &refresh_interval)) 1107 return; 1108 1109 if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) { 1110 edata->state = ENVSYS_SINVALID; 1111 } else { 1112 edata->value_cur = val * 1000000 + 273150000; 1113 edata->state = ENVSYS_SVALID; 1114 } 1115 } 1116 1117 static void 1118 lom1_write_hostname(struct lom_softc *sc) 1119 { 1120 char name[(LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1) + 1]; 1121 char *p; 1122 int i; 1123 1124 /* 1125 * LOMlite generally doesn't have enough space to store the 1126 * fully qualified hostname. If the hostname is too long, 1127 * strip off the domain name. 1128 */ 1129 strlcpy(name, hostname, sizeof(name)); 1130 if (hostnamelen >= sizeof(name)) { 1131 p = strchr(name, '.'); 1132 if (p) 1133 *p = '\0'; 1134 } 1135 1136 for (i = 0; i < strlen(name) + 1; i++) 1137 if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i])) 1138 break; 1139 } 1140 1141 static void 1142 lom2_write_hostname(struct lom_softc *sc) 1143 { 1144 int i; 1145 1146 lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1); 1147 for (i = 0; i < hostnamelen + 1; i++) 1148 lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]); 1149 } 1150 1151 static int 1152 lom_wdog_tickle(struct sysmon_wdog *smw) 1153 { 1154 struct lom_softc *sc = smw->smw_cookie; 1155 1156 /* Pat the dog. */ 1157 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 1158 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 1159 lom_queue_cmd(sc, &sc->sc_wdog_pat); 1160 1161 return 0; 1162 } 1163 1164 static int 1165 lom_wdog_setmode(struct sysmon_wdog *smw) 1166 { 1167 struct lom_softc *sc = smw->smw_cookie; 1168 1169 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 1170 /* disable watchdog */ 1171 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET); 1172 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1173 } else { 1174 if (smw->smw_period == WDOG_PERIOD_DEFAULT) 1175 smw->smw_period = sc->sc_wdog_period; 1176 else if (smw->smw_period == 0 || 1177 smw->smw_period > LOM_WDOG_TIME_MAX) 1178 return EINVAL; 1179 lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period); 1180 1181 /* enable watchdog */ 1182 lom_dequeue_cmd(sc, &sc->sc_wdog_pat); 1183 sc->sc_wdog_ctl |= LOM_WDOG_ENABLE|LOM_WDOG_RESET; 1184 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 1185 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 1186 lom_queue_cmd(sc, &sc->sc_wdog_pat); 1187 } 1188 1189 return 0; 1190 } 1191 1192 static bool 1193 lom_shutdown(device_t dev, int how) 1194 { 1195 struct lom_softc *sc = device_private(dev); 1196 1197 sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE; 1198 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1199 return true; 1200 } 1201 1202 SYSCTL_SETUP(sysctl_lom_setup, "sysctl hw.lom subtree setup") 1203 { 1204 const struct sysctlnode *node; 1205 1206 if (sysctl_createv(clog, 0, NULL, &node, 1207 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL, 1208 NULL, 0, NULL, 0, CTL_HW, CTL_EOL) != 0) 1209 return; 1210 1211 hw_node = node->sysctl_num; 1212 } 1213 1214 static int 1215 lom_sysctl_alarm(SYSCTLFN_ARGS) 1216 { 1217 struct sysctlnode node; 1218 struct lom_softc *sc; 1219 int i, tmp, error; 1220 uint8_t val; 1221 1222 node = *rnode; 1223 sc = node.sysctl_data; 1224 1225 for (i = 0; i < sc->sc_num_alarm; i++) { 1226 if (node.sysctl_num == sc->sc_sysctl_num[i]) { 1227 lom_refresh_alarm(sc, &sc->sc_alarm[i], i); 1228 tmp = sc->sc_alarm[i].value_cur; 1229 node.sysctl_data = &tmp; 1230 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1231 if (error || newp == NULL) 1232 return error; 1233 if (tmp < 0 || tmp > 1) 1234 return EINVAL; 1235 1236 if (lom_read(sc, LOM_IDX_ALARM, &val)) 1237 return EINVAL; 1238 if (i == 0) { 1239 /* Fault LED */ 1240 if (tmp != 0) 1241 val &= ~LOM_ALARM_FAULT; 1242 else 1243 val |= LOM_ALARM_FAULT; 1244 } else { 1245 /* Alarms */ 1246 if (tmp != 0) 1247 val |= LOM_ALARM_1 << (i - 1); 1248 else 1249 val &= ~(LOM_ALARM_1 << (i - 1)); 1250 } 1251 if (lom_write(sc, LOM_IDX_ALARM, val)) 1252 return EINVAL; 1253 1254 sc->sc_alarm[i].value_cur = tmp; 1255 return 0; 1256 } 1257 } 1258 1259 return ENOENT; 1260 } 1261