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