1 /* $OpenBSD: lom.c,v 1.22 2010/05/28 10:02:44 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2009 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/device.h> 20 #include <sys/kernel.h> 21 #include <sys/proc.h> 22 #include <sys/sensors.h> 23 #include <sys/systm.h> 24 #include <sys/timeout.h> 25 26 #include <machine/autoconf.h> 27 #include <machine/openfirm.h> 28 29 #include <sparc64/dev/ebusreg.h> 30 #include <sparc64/dev/ebusvar.h> 31 32 /* 33 * LOMlite is a so far unidentified microcontroller. 34 */ 35 #define LOM1_STATUS 0x00 /* R */ 36 #define LOM1_STATUS_BUSY 0x80 37 #define LOM1_CMD 0x00 /* W */ 38 #define LOM1_DATA 0x01 /* R/W */ 39 40 /* 41 * LOMlite2 is implemented as a H8/3437 microcontroller which has its 42 * on-chip host interface hooked up to EBus. 43 */ 44 #define LOM2_DATA 0x00 /* R/W */ 45 #define LOM2_CMD 0x01 /* W */ 46 #define LOM2_STATUS 0x01 /* R */ 47 #define LOM2_STATUS_OBF 0x01 /* Output Buffer Full */ 48 #define LOM2_STATUS_IBF 0x02 /* Input Buffer Full */ 49 50 #define LOM_IDX_CMD 0x00 51 #define LOM_IDX_CMD_GENERIC 0x00 52 #define LOM_IDX_CMD_TEMP 0x04 53 #define LOM_IDX_CMD_FAN 0x05 54 55 #define LOM_IDX_FW_REV 0x01 /* Firmware revision */ 56 57 #define LOM_IDX_FAN1 0x04 /* Fan speed */ 58 #define LOM_IDX_FAN2 0x05 59 #define LOM_IDX_FAN3 0x06 60 #define LOM_IDX_FAN4 0x07 61 #define LOM_IDX_PSU1 0x08 /* PSU status */ 62 #define LOM_IDX_PSU2 0x09 63 #define LOM_IDX_PSU3 0x0a 64 #define LOM_PSU_INPUTA 0x01 65 #define LOM_PSU_INPUTB 0x02 66 #define LOM_PSU_OUTPUT 0x04 67 #define LOM_PSU_PRESENT 0x08 68 #define LOM_PSU_STANDBY 0x10 69 70 #define LOM_IDX_TEMP1 0x18 /* Temperature */ 71 #define LOM_IDX_TEMP2 0x19 72 #define LOM_IDX_TEMP3 0x1a 73 #define LOM_IDX_TEMP4 0x1b 74 #define LOM_IDX_TEMP5 0x1c 75 #define LOM_IDX_TEMP6 0x1d 76 #define LOM_IDX_TEMP7 0x1e 77 #define LOM_IDX_TEMP8 0x1f 78 79 #define LOM_IDX_LED1 0x25 80 81 #define LOM_IDX_ALARM 0x30 82 #define LOM_IDX_WDOG_CTL 0x31 83 #define LOM_WDOG_ENABLE 0x01 84 #define LOM_WDOG_RESET 0x02 85 #define LOM_WDOG_AL3_WDOG 0x04 86 #define LOM_WDOG_AL3_FANPSU 0x08 87 #define LOM_IDX_WDOG_TIME 0x32 88 #define LOM_WDOG_TIME_MAX 126 89 90 #define LOM1_IDX_HOSTNAME1 0x33 91 #define LOM1_IDX_HOSTNAME2 0x34 92 #define LOM1_IDX_HOSTNAME3 0x35 93 #define LOM1_IDX_HOSTNAME4 0x36 94 #define LOM1_IDX_HOSTNAME5 0x37 95 #define LOM1_IDX_HOSTNAME6 0x38 96 #define LOM1_IDX_HOSTNAME7 0x39 97 #define LOM1_IDX_HOSTNAME8 0x3a 98 #define LOM1_IDX_HOSTNAME9 0x3b 99 #define LOM1_IDX_HOSTNAME10 0x3c 100 #define LOM1_IDX_HOSTNAME11 0x3d 101 #define LOM1_IDX_HOSTNAME12 0x3e 102 103 #define LOM2_IDX_HOSTNAMELEN 0x38 104 #define LOM2_IDX_HOSTNAME 0x39 105 106 #define LOM_IDX_CONFIG 0x5d 107 #define LOM_IDX_FAN1_CAL 0x5e 108 #define LOM_IDX_FAN2_CAL 0x5f 109 #define LOM_IDX_FAN3_CAL 0x60 110 #define LOM_IDX_FAN4_CAL 0x61 111 #define LOM_IDX_FAN1_LOW 0x62 112 #define LOM_IDX_FAN2_LOW 0x63 113 #define LOM_IDX_FAN3_LOW 0x64 114 #define LOM_IDX_FAN4_LOW 0x65 115 116 #define LOM_IDX_CONFIG2 0x66 117 #define LOM_IDX_CONFIG3 0x67 118 119 #define LOM_IDX_PROBE55 0x7e /* Always returns 0x55 */ 120 #define LOM_IDX_PROBEAA 0x7f /* Always returns 0xaa */ 121 122 #define LOM_IDX_WRITE 0x80 123 124 #define LOM_IDX4_TEMP_NAME_START 0x40 125 #define LOM_IDX4_TEMP_NAME_END 0xff 126 127 #define LOM_IDX5_FAN_NAME_START 0x40 128 #define LOM_IDX5_FAN_NAME_END 0xff 129 130 #define LOM_MAX_FAN 4 131 #define LOM_MAX_PSU 3 132 #define LOM_MAX_TEMP 8 133 134 struct lom_cmd { 135 uint8_t lc_cmd; 136 uint8_t lc_data; 137 138 TAILQ_ENTRY(lom_cmd) lc_next; 139 }; 140 141 struct lom_softc { 142 struct device sc_dev; 143 bus_space_tag_t sc_iot; 144 bus_space_handle_t sc_ioh; 145 146 int sc_type; 147 #define LOM_LOMLITE 0 148 #define LOM_LOMLITE2 2 149 int sc_space; 150 151 struct ksensor sc_fan[LOM_MAX_FAN]; 152 struct ksensor sc_psu[LOM_MAX_PSU]; 153 struct ksensor sc_temp[LOM_MAX_TEMP]; 154 struct ksensordev sc_sensordev; 155 156 int sc_num_fan; 157 int sc_num_psu; 158 int sc_num_temp; 159 160 uint8_t sc_fan_cal[LOM_MAX_FAN]; 161 uint8_t sc_fan_low[LOM_MAX_FAN]; 162 163 char sc_hostname[MAXHOSTNAMELEN]; 164 165 struct timeout sc_wdog_to; 166 int sc_wdog_period; 167 uint8_t sc_wdog_ctl; 168 struct lom_cmd sc_wdog_pat; 169 170 TAILQ_HEAD(, lom_cmd) sc_queue; 171 struct mutex sc_queue_mtx; 172 struct timeout sc_state_to; 173 int sc_state; 174 #define LOM_STATE_IDLE 0 175 #define LOM_STATE_CMD 1 176 #define LOM_STATE_DATA 2 177 int sc_retry; 178 }; 179 180 int lom_match(struct device *, void *, void *); 181 void lom_attach(struct device *, struct device *, void *); 182 183 struct cfattach lom_ca = { 184 sizeof(struct lom_softc), lom_match, lom_attach 185 }; 186 187 struct cfdriver lom_cd = { 188 NULL, "lom", DV_DULL 189 }; 190 191 int lom_read(struct lom_softc *, uint8_t, uint8_t *); 192 int lom_write(struct lom_softc *, uint8_t, uint8_t); 193 void lom_queue_cmd(struct lom_softc *, struct lom_cmd *); 194 void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *); 195 int lom1_read(struct lom_softc *, uint8_t, uint8_t *); 196 int lom1_write(struct lom_softc *, uint8_t, uint8_t); 197 int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *); 198 int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t); 199 void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *); 200 void lom1_process_queue(void *); 201 void lom1_process_queue_locked(struct lom_softc *); 202 int lom2_read(struct lom_softc *, uint8_t, uint8_t *); 203 int lom2_write(struct lom_softc *, uint8_t, uint8_t); 204 int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *); 205 int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t); 206 void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *); 207 int lom2_intr(void *); 208 209 int lom_init_desc(struct lom_softc *sc); 210 void lom_refresh(void *); 211 void lom1_write_hostname(struct lom_softc *); 212 void lom2_write_hostname(struct lom_softc *); 213 214 void lom_wdog_pat(void *); 215 int lom_wdog_cb(void *, int); 216 217 void lom_shutdown(void *); 218 219 int 220 lom_match(struct device *parent, void *match, void *aux) 221 { 222 struct ebus_attach_args *ea = aux; 223 224 if (strcmp(ea->ea_name, "SUNW,lom") == 0 || 225 strcmp(ea->ea_name, "SUNW,lomh") == 0) 226 return (1); 227 228 return (0); 229 } 230 231 void 232 lom_attach(struct device *parent, struct device *self, void *aux) 233 { 234 struct lom_softc *sc = (void *)self; 235 struct ebus_attach_args *ea = aux; 236 uint8_t reg, fw_rev, config, config2, config3; 237 uint8_t cal, low; 238 int i; 239 240 if (strcmp(ea->ea_name, "SUNW,lomh") == 0) { 241 if (ea->ea_nintrs < 1) { 242 printf(": no interrupt\n"); 243 return; 244 } 245 sc->sc_type = LOM_LOMLITE2; 246 } 247 248 if (ebus_bus_map(ea->ea_iotag, 0, 249 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 250 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 251 sc->sc_iot = ea->ea_iotag; 252 } else if (ebus_bus_map(ea->ea_memtag, 0, 253 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 254 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 255 sc->sc_iot = ea->ea_memtag; 256 } else { 257 printf(": can't map register space\n"); 258 return; 259 } 260 261 if (sc->sc_type < LOM_LOMLITE2) { 262 /* XXX Magic */ 263 bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0); 264 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca); 265 } 266 267 if (lom_read(sc, LOM_IDX_PROBE55, ®) || reg != 0x55 || 268 lom_read(sc, LOM_IDX_PROBEAA, ®) || reg != 0xaa || 269 lom_read(sc, LOM_IDX_FW_REV, &fw_rev) || 270 lom_read(sc, LOM_IDX_CONFIG, &config)) 271 { 272 printf(": not responding\n"); 273 return; 274 } 275 276 TAILQ_INIT(&sc->sc_queue); 277 mtx_init(&sc->sc_queue_mtx, IPL_BIO); 278 279 config2 = config3 = 0; 280 if (sc->sc_type < LOM_LOMLITE2) { 281 /* 282 * LOMlite doesn't do interrupts so we limp along on 283 * timeouts. 284 */ 285 timeout_set(&sc->sc_state_to, lom1_process_queue, sc); 286 } else { 287 lom_read(sc, LOM_IDX_CONFIG2, &config2); 288 lom_read(sc, LOM_IDX_CONFIG3, &config3); 289 290 bus_intr_establish(sc->sc_iot, ea->ea_intrs[0], 291 IPL_BIO, 0, lom2_intr, sc, self->dv_xname); 292 } 293 294 sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN); 295 sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU); 296 sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP); 297 298 for (i = 0; i < sc->sc_num_fan; i++) { 299 if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) || 300 lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) { 301 printf(": can't read fan information\n"); 302 return; 303 } 304 sc->sc_fan_cal[i] = cal; 305 sc->sc_fan_low[i] = low; 306 } 307 308 /* Initialize sensor data. */ 309 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 310 sizeof(sc->sc_sensordev.xname)); 311 for (i = 0; i < sc->sc_num_fan; i++) { 312 sc->sc_fan[i].type = SENSOR_FANRPM; 313 sensor_attach(&sc->sc_sensordev, &sc->sc_fan[i]); 314 snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc), 315 "fan%d", i + 1); 316 } 317 for (i = 0; i < sc->sc_num_psu; i++) { 318 sc->sc_psu[i].type = SENSOR_INDICATOR; 319 sensor_attach(&sc->sc_sensordev, &sc->sc_psu[i]); 320 snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc), 321 "PSU%d", i + 1); 322 } 323 for (i = 0; i < sc->sc_num_temp; i++) { 324 sc->sc_temp[i].type = SENSOR_TEMP; 325 sensor_attach(&sc->sc_sensordev, &sc->sc_temp[i]); 326 } 327 if (lom_init_desc(sc)) { 328 printf(": can't read sensor names\n"); 329 return; 330 } 331 332 if (sensor_task_register(sc, lom_refresh, 5) == NULL) { 333 printf(": unable to register update task\n"); 334 return; 335 } 336 337 sensordev_install(&sc->sc_sensordev); 338 339 /* 340 * We configure the watchdog to turn on the fault LED when the 341 * watchdog timer expires. We run our own timeout to pat it 342 * such that this won't happen unless the kernel hangs. When 343 * the watchdog is explicitly configured using sysctl(8), we 344 * reconfigure it to reset the machine and let the standard 345 * watchdog(4) machinery take over. 346 */ 347 lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 348 lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl); 349 sc->sc_wdog_ctl &= ~LOM_WDOG_RESET; 350 sc->sc_wdog_ctl |= LOM_WDOG_ENABLE; 351 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 352 timeout_set(&sc->sc_wdog_to, lom_wdog_pat, sc); 353 timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 354 355 wdog_register(sc, lom_wdog_cb); 356 357 printf(": %s rev %d.%d\n", 358 sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2", 359 fw_rev >> 4, fw_rev & 0x0f); 360 361 shutdownhook_establish(lom_shutdown, sc); 362 } 363 364 int 365 lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 366 { 367 if (sc->sc_type < LOM_LOMLITE2) 368 return lom1_read(sc, reg, val); 369 else 370 return lom2_read(sc, reg, val); 371 } 372 373 int 374 lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 375 { 376 if (sc->sc_type < LOM_LOMLITE2) 377 return lom1_write(sc, reg, val); 378 else 379 return lom2_write(sc, reg, val); 380 } 381 382 void 383 lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 384 { 385 if (sc->sc_type < LOM_LOMLITE2) 386 return lom1_queue_cmd(sc, lc); 387 else 388 return lom2_queue_cmd(sc, lc); 389 } 390 391 void 392 lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 393 { 394 struct lom_cmd *lcp; 395 396 mtx_enter(&sc->sc_queue_mtx); 397 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) { 398 if (lcp == lc) { 399 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 400 break; 401 } 402 } 403 mtx_leave(&sc->sc_queue_mtx); 404 } 405 406 int 407 lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 408 { 409 struct lom_cmd lc; 410 int error; 411 412 if (cold) 413 return lom1_read_polled(sc, reg, val); 414 415 lc.lc_cmd = reg; 416 lc.lc_data = 0xff; 417 lom1_queue_cmd(sc, &lc); 418 419 error = tsleep(&lc, PZERO, "lomrd", hz); 420 if (error) 421 lom_dequeue_cmd(sc, &lc); 422 423 *val = lc.lc_data; 424 425 return (error); 426 } 427 428 int 429 lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 430 { 431 struct lom_cmd lc; 432 int error; 433 434 if (cold) 435 return lom1_write_polled(sc, reg, val); 436 437 lc.lc_cmd = reg | LOM_IDX_WRITE; 438 lc.lc_data = val; 439 lom1_queue_cmd(sc, &lc); 440 441 error = tsleep(&lc, PZERO, "lomwr", 2 * hz); 442 if (error) 443 lom_dequeue_cmd(sc, &lc); 444 445 return (error); 446 } 447 448 int 449 lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 450 { 451 uint8_t str; 452 int i; 453 454 /* Wait for input buffer to become available. */ 455 for (i = 30; i > 0; i--) { 456 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 457 delay(1000); 458 if ((str & LOM1_STATUS_BUSY) == 0) 459 break; 460 } 461 if (i == 0) 462 return (ETIMEDOUT); 463 464 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 465 466 /* Wait until the microcontroller fills output buffer. */ 467 for (i = 30; i > 0; i--) { 468 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 469 delay(1000); 470 if ((str & LOM1_STATUS_BUSY) == 0) 471 break; 472 } 473 if (i == 0) 474 return (ETIMEDOUT); 475 476 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 477 return (0); 478 } 479 480 int 481 lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 482 { 483 uint8_t str; 484 int i; 485 486 /* Wait for input buffer to become available. */ 487 for (i = 30; i > 0; i--) { 488 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 489 delay(1000); 490 if ((str & LOM1_STATUS_BUSY) == 0) 491 break; 492 } 493 if (i == 0) 494 return (ETIMEDOUT); 495 496 reg |= LOM_IDX_WRITE; 497 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg); 498 499 /* Wait until the microcontroller fills output buffer. */ 500 for (i = 30; i > 0; i--) { 501 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 502 delay(1000); 503 if ((str & LOM1_STATUS_BUSY) == 0) 504 break; 505 } 506 if (i == 0) 507 return (ETIMEDOUT); 508 509 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val); 510 511 return (0); 512 } 513 514 void 515 lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 516 { 517 mtx_enter(&sc->sc_queue_mtx); 518 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 519 if (sc->sc_state == LOM_STATE_IDLE) { 520 sc->sc_state = LOM_STATE_CMD; 521 lom1_process_queue_locked(sc); 522 } 523 mtx_leave(&sc->sc_queue_mtx); 524 } 525 526 void 527 lom1_process_queue(void *arg) 528 { 529 struct lom_softc *sc = arg; 530 531 mtx_enter(&sc->sc_queue_mtx); 532 lom1_process_queue_locked(sc); 533 mtx_leave(&sc->sc_queue_mtx); 534 } 535 536 void 537 lom1_process_queue_locked(struct lom_softc *sc) 538 { 539 struct lom_cmd *lc; 540 uint8_t str; 541 542 lc = TAILQ_FIRST(&sc->sc_queue); 543 if (lc == NULL) { 544 sc->sc_state = LOM_STATE_IDLE; 545 return; 546 } 547 548 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS); 549 if (str & LOM1_STATUS_BUSY) { 550 if (sc->sc_retry++ < 30) { 551 timeout_add_msec(&sc->sc_state_to, 1); 552 return; 553 } 554 555 /* 556 * Looks like the microcontroller got wedged. Unwedge 557 * it by writing this magic value. Give it some time 558 * to recover. 559 */ 560 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac); 561 timeout_add_msec(&sc->sc_state_to, 1000); 562 sc->sc_state = LOM_STATE_CMD; 563 return; 564 } 565 566 sc->sc_retry = 0; 567 568 if (sc->sc_state == LOM_STATE_CMD) { 569 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd); 570 sc->sc_state = LOM_STATE_DATA; 571 timeout_add_msec(&sc->sc_state_to, 250); 572 return; 573 } 574 575 KASSERT(sc->sc_state == LOM_STATE_DATA); 576 if ((lc->lc_cmd & LOM_IDX_WRITE) == 0) 577 lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA); 578 else 579 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data); 580 581 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 582 583 wakeup(lc); 584 585 if (!TAILQ_EMPTY(&sc->sc_queue)) { 586 sc->sc_state = LOM_STATE_CMD; 587 timeout_add_msec(&sc->sc_state_to, 1); 588 return; 589 } 590 591 sc->sc_state = LOM_STATE_IDLE; 592 } 593 594 int 595 lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val) 596 { 597 struct lom_cmd lc; 598 int error; 599 600 if (cold) 601 return lom2_read_polled(sc, reg, val); 602 603 lc.lc_cmd = reg; 604 lc.lc_data = 0xff; 605 lom2_queue_cmd(sc, &lc); 606 607 error = tsleep(&lc, PZERO, "lom2rd", hz); 608 if (error) 609 lom_dequeue_cmd(sc, &lc); 610 611 *val = lc.lc_data; 612 613 return (error); 614 } 615 616 int 617 lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val) 618 { 619 uint8_t str; 620 int i; 621 622 /* Wait for input buffer to become available. */ 623 for (i = 1000; i > 0; i--) { 624 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 625 delay(10); 626 if ((str & LOM2_STATUS_IBF) == 0) 627 break; 628 } 629 if (i == 0) 630 return (ETIMEDOUT); 631 632 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 633 634 /* Wait until the microcontroller fills output buffer. */ 635 for (i = 1000; i > 0; i--) { 636 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 637 delay(10); 638 if (str & LOM2_STATUS_OBF) 639 break; 640 } 641 if (i == 0) 642 return (ETIMEDOUT); 643 644 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 645 return (0); 646 } 647 648 int 649 lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val) 650 { 651 struct lom_cmd lc; 652 int error; 653 654 if (cold) 655 return lom2_write_polled(sc, reg, val); 656 657 lc.lc_cmd = reg | LOM_IDX_WRITE; 658 lc.lc_data = val; 659 lom2_queue_cmd(sc, &lc); 660 661 error = tsleep(&lc, PZERO, "lom2wr", hz); 662 if (error) 663 lom_dequeue_cmd(sc, &lc); 664 665 return (error); 666 } 667 668 int 669 lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val) 670 { 671 uint8_t str; 672 int i; 673 674 /* Wait for input buffer to become available. */ 675 for (i = 1000; i > 0; i--) { 676 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 677 delay(10); 678 if ((str & LOM2_STATUS_IBF) == 0) 679 break; 680 } 681 if (i == 0) 682 return (ETIMEDOUT); 683 684 if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD) 685 reg |= LOM_IDX_WRITE; 686 687 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg); 688 689 /* Wait until the microcontroller fills output buffer. */ 690 for (i = 1000; i > 0; i--) { 691 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 692 delay(10); 693 if (str & LOM2_STATUS_OBF) 694 break; 695 } 696 if (i == 0) 697 return (ETIMEDOUT); 698 699 bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 700 701 /* Wait for input buffer to become available. */ 702 for (i = 1000; i > 0; i--) { 703 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 704 delay(10); 705 if ((str & LOM2_STATUS_IBF) == 0) 706 break; 707 } 708 if (i == 0) 709 return (ETIMEDOUT); 710 711 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val); 712 713 /* Wait until the microcontroller fills output buffer. */ 714 for (i = 1000; i > 0; i--) { 715 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 716 delay(10); 717 if (str & LOM2_STATUS_OBF) 718 break; 719 } 720 if (i == 0) 721 return (ETIMEDOUT); 722 723 bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 724 725 /* If we switched spaces, remember the one we're in now. */ 726 if (reg == LOM_IDX_CMD) 727 sc->sc_space = val; 728 729 return (0); 730 } 731 732 void 733 lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc) 734 { 735 uint8_t str; 736 737 mtx_enter(&sc->sc_queue_mtx); 738 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next); 739 if (sc->sc_state == LOM_STATE_IDLE) { 740 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 741 if ((str & LOM2_STATUS_IBF) == 0) { 742 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 743 LOM2_CMD, lc->lc_cmd); 744 sc->sc_state = LOM_STATE_DATA; 745 } 746 } 747 mtx_leave(&sc->sc_queue_mtx); 748 } 749 750 int 751 lom2_intr(void *arg) 752 { 753 struct lom_softc *sc = arg; 754 struct lom_cmd *lc; 755 uint8_t str, obr; 756 757 mtx_enter(&sc->sc_queue_mtx); 758 759 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 760 obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA); 761 762 lc = TAILQ_FIRST(&sc->sc_queue); 763 if (lc == NULL) { 764 mtx_leave(&sc->sc_queue_mtx); 765 return (0); 766 } 767 768 if (lc->lc_cmd & LOM_IDX_WRITE) { 769 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 770 LOM2_DATA, lc->lc_data); 771 lc->lc_cmd &= ~LOM_IDX_WRITE; 772 mtx_leave(&sc->sc_queue_mtx); 773 return (1); 774 } 775 776 KASSERT(sc->sc_state = LOM_STATE_DATA); 777 lc->lc_data = obr; 778 779 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next); 780 781 wakeup(lc); 782 783 sc->sc_state = LOM_STATE_IDLE; 784 785 if (!TAILQ_EMPTY(&sc->sc_queue)) { 786 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS); 787 if ((str & LOM2_STATUS_IBF) == 0) { 788 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 789 LOM2_CMD, lc->lc_cmd); 790 sc->sc_state = LOM_STATE_DATA; 791 } 792 } 793 794 mtx_leave(&sc->sc_queue_mtx); 795 796 return (1); 797 } 798 799 int 800 lom_init_desc(struct lom_softc *sc) 801 { 802 uint8_t val; 803 int i, j, k; 804 int error; 805 806 /* LOMlite doesn't provide sensor descriptions. */ 807 if (sc->sc_type < LOM_LOMLITE2) 808 return (0); 809 810 /* 811 * Read temperature sensor names. 812 */ 813 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP); 814 if (error) 815 return (error); 816 817 i = 0; 818 j = 0; 819 k = LOM_IDX4_TEMP_NAME_START; 820 while (k <= LOM_IDX4_TEMP_NAME_END) { 821 error = lom_read(sc, k++, &val); 822 if (error) 823 goto fail; 824 825 if (val == 0xff) 826 break; 827 828 if (j < sizeof (sc->sc_temp[i].desc) - 1) 829 sc->sc_temp[i].desc[j++] = val; 830 831 if (val == '\0') { 832 i++; 833 j = 0; 834 if (i < sc->sc_num_temp) 835 continue; 836 837 break; 838 } 839 } 840 841 /* 842 * Read fan names. 843 */ 844 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN); 845 if (error) 846 return (error); 847 848 i = 0; 849 j = 0; 850 k = LOM_IDX5_FAN_NAME_START; 851 while (k <= LOM_IDX5_FAN_NAME_END) { 852 error = lom_read(sc, k++, &val); 853 if (error) 854 goto fail; 855 856 if (val == 0xff) 857 break; 858 859 if (j < sizeof (sc->sc_fan[i].desc) - 1) 860 sc->sc_fan[i].desc[j++] = val; 861 862 if (val == '\0') { 863 i++; 864 j = 0; 865 if (i < sc->sc_num_fan) 866 continue; 867 868 break; 869 } 870 } 871 872 fail: 873 lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC); 874 return (error); 875 } 876 877 void 878 lom_refresh(void *arg) 879 { 880 struct lom_softc *sc = arg; 881 uint8_t val; 882 int i; 883 884 for (i = 0; i < sc->sc_num_fan; i++) { 885 if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) { 886 sc->sc_fan[i].flags |= SENSOR_FINVALID; 887 continue; 888 } 889 890 sc->sc_fan[i].value = (60 * sc->sc_fan_cal[i] * val) / 100; 891 if (val < sc->sc_fan_low[i]) 892 sc->sc_fan[i].status = SENSOR_S_CRIT; 893 else 894 sc->sc_fan[i].status = SENSOR_S_OK; 895 sc->sc_fan[i].flags &= ~SENSOR_FINVALID; 896 } 897 898 for (i = 0; i < sc->sc_num_psu; i++) { 899 if (lom_read(sc, LOM_IDX_PSU1 + i, &val) || 900 !ISSET(val, LOM_PSU_PRESENT)) { 901 sc->sc_psu[i].flags |= SENSOR_FINVALID; 902 continue; 903 } 904 905 if (val & LOM_PSU_STANDBY) { 906 sc->sc_psu[i].value = 0; 907 sc->sc_psu[i].status = SENSOR_S_UNSPEC; 908 } else { 909 sc->sc_psu[i].value = 1; 910 if (ISSET(val, LOM_PSU_INPUTA) && 911 ISSET(val, LOM_PSU_INPUTB) && 912 ISSET(val, LOM_PSU_OUTPUT)) 913 sc->sc_psu[i].status = SENSOR_S_OK; 914 else 915 sc->sc_psu[i].status = SENSOR_S_CRIT; 916 } 917 sc->sc_psu[i].flags &= ~SENSOR_FINVALID; 918 } 919 920 for (i = 0; i < sc->sc_num_temp; i++) { 921 if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) { 922 sc->sc_temp[i].flags |= SENSOR_FINVALID; 923 continue; 924 } 925 926 sc->sc_temp[i].value = val * 1000000 + 273150000; 927 sc->sc_temp[i].flags &= ~SENSOR_FINVALID; 928 } 929 930 /* 931 * If our hostname is set and differs from what's stored in 932 * the LOM, write the new hostname back to the LOM. Note that 933 * we include the terminating NUL when writing the hostname 934 * back to the LOM, otherwise the LOM will print any trailing 935 * garbage. 936 */ 937 if (hostnamelen > 0 && 938 strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) { 939 if (sc->sc_type < LOM_LOMLITE2) 940 lom1_write_hostname(sc); 941 else 942 lom2_write_hostname(sc); 943 strlcpy(sc->sc_hostname, hostname, sizeof(hostname)); 944 } 945 } 946 947 void 948 lom1_write_hostname(struct lom_softc *sc) 949 { 950 char name[(LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1) + 1]; 951 char *p; 952 int i; 953 954 /* 955 * LOMlite generally doesn't have enough space to store the 956 * fully qualified hostname. If the hostname is too long, 957 * strip off the domain name. 958 */ 959 strlcpy(name, hostname, sizeof(name)); 960 if (hostnamelen >= sizeof(name)) { 961 p = strchr(name, '.'); 962 if (p) 963 *p = '\0'; 964 } 965 966 for (i = 0; i < strlen(name) + 1; i++) 967 if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i])) 968 break; 969 } 970 971 void 972 lom2_write_hostname(struct lom_softc *sc) 973 { 974 int i; 975 976 lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1); 977 for (i = 0; i < hostnamelen + 1; i++) 978 lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]); 979 } 980 981 void 982 lom_wdog_pat(void *arg) 983 { 984 struct lom_softc *sc = arg; 985 986 /* Pat the dog. */ 987 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 988 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 989 lom_queue_cmd(sc, &sc->sc_wdog_pat); 990 991 timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 992 } 993 994 int 995 lom_wdog_cb(void *arg, int period) 996 { 997 struct lom_softc *sc = arg; 998 999 if (period > LOM_WDOG_TIME_MAX) 1000 period = LOM_WDOG_TIME_MAX; 1001 else if (period < 0) 1002 period = 0; 1003 1004 if (period == 0) { 1005 if (sc->sc_wdog_period != 0) { 1006 /* Stop watchdog from resetting the machine. */ 1007 sc->sc_wdog_ctl &= ~LOM_WDOG_RESET; 1008 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1009 1010 lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX); 1011 timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2); 1012 } 1013 } else { 1014 if (sc->sc_wdog_period != period) { 1015 /* Set new timeout. */ 1016 lom_write(sc, LOM_IDX_WDOG_TIME, period); 1017 } 1018 if (sc->sc_wdog_period == 0) { 1019 /* Make watchdog reset the machine. */ 1020 sc->sc_wdog_ctl |= LOM_WDOG_RESET; 1021 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1022 1023 timeout_del(&sc->sc_wdog_to); 1024 } else { 1025 /* Pat the dog. */ 1026 lom_dequeue_cmd(sc, &sc->sc_wdog_pat); 1027 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE; 1028 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl; 1029 lom_queue_cmd(sc, &sc->sc_wdog_pat); 1030 } 1031 } 1032 sc->sc_wdog_period = period; 1033 1034 return (period); 1035 } 1036 1037 void 1038 lom_shutdown(void *arg) 1039 { 1040 struct lom_softc *sc = arg; 1041 1042 sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE; 1043 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl); 1044 } 1045