Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / sparc64 / dev / lom.c
blob24f66b7b36bbf4d524ba59a76ca7c7798cbbfa2b
1 /* $NetBSD: lom.c,v 1.3 2009/11/28 04:14:27 nakayama Exp $ */
2 /* $OpenBSD: lom.c,v 1.20 2009/12/12 13:01:00 kettenis Exp $ */
3 /*
4 * Copyright (c) 2009 Mark Kettenis
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.
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.
19 #include <sys/cdefs.h>
20 __KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.3 2009/11/28 04:14:27 nakayama Exp $");
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>
30 #include <machine/autoconf.h>
32 #include <dev/ebus/ebusreg.h>
33 #include <dev/ebus/ebusvar.h>
34 #include <dev/sysmon/sysmonvar.h>
37 * LOMlite is a so far unidentified microcontroller.
39 #define LOM1_STATUS 0x00 /* R */
40 #define LOM1_STATUS_BUSY 0x80
41 #define LOM1_CMD 0x00 /* W */
42 #define LOM1_DATA 0x01 /* R/W */
45 * LOMlite2 is implemented as a H8/3437 microcontroller which has its
46 * on-chip host interface hooked up to EBus.
48 #define LOM2_DATA 0x00 /* R/W */
49 #define LOM2_CMD 0x01 /* W */
50 #define LOM2_STATUS 0x01 /* R */
51 #define LOM2_STATUS_OBF 0x01 /* Output Buffer Full */
52 #define LOM2_STATUS_IBF 0x02 /* Input Buffer Full */
54 #define LOM_IDX_CMD 0x00
55 #define LOM_IDX_CMD_GENERIC 0x00
56 #define LOM_IDX_CMD_TEMP 0x04
57 #define LOM_IDX_CMD_FAN 0x05
59 #define LOM_IDX_FW_REV 0x01 /* Firmware revision */
61 #define LOM_IDX_FAN1 0x04 /* Fan speed */
62 #define LOM_IDX_FAN2 0x05
63 #define LOM_IDX_FAN3 0x06
64 #define LOM_IDX_FAN4 0x07
65 #define LOM_IDX_PSU1 0x08 /* PSU status */
66 #define LOM_IDX_PSU2 0x09
67 #define LOM_IDX_PSU3 0x0a
68 #define LOM_PSU_INPUTA 0x01
69 #define LOM_PSU_INPUTB 0x02
70 #define LOM_PSU_OUTPUT 0x04
71 #define LOM_PSU_PRESENT 0x08
72 #define LOM_PSU_STANDBY 0x10
74 #define LOM_IDX_TEMP1 0x18 /* Temperature */
75 #define LOM_IDX_TEMP2 0x19
76 #define LOM_IDX_TEMP3 0x1a
77 #define LOM_IDX_TEMP4 0x1b
78 #define LOM_IDX_TEMP5 0x1c
79 #define LOM_IDX_TEMP6 0x1d
80 #define LOM_IDX_TEMP7 0x1e
81 #define LOM_IDX_TEMP8 0x1f
83 #define LOM_IDX_LED1 0x25
85 #define LOM_IDX_ALARM 0x30
86 #define LOM_ALARM_1 0x01
87 #define LOM_ALARM_2 0x02
88 #define LOM_ALARM_3 0x04
89 #define LOM_ALARM_FAULT 0xf0
90 #define LOM_IDX_WDOG_CTL 0x31
91 #define LOM_WDOG_ENABLE 0x01
92 #define LOM_WDOG_RESET 0x02
93 #define LOM_WDOG_AL3_WDOG 0x04
94 #define LOM_WDOG_AL3_FANPSU 0x08
95 #define LOM_IDX_WDOG_TIME 0x32
96 #define LOM_WDOG_TIME_MAX 126
98 #define LOM1_IDX_HOSTNAME1 0x33
99 #define LOM1_IDX_HOSTNAME2 0x34
100 #define LOM1_IDX_HOSTNAME3 0x35
101 #define LOM1_IDX_HOSTNAME4 0x36
102 #define LOM1_IDX_HOSTNAME5 0x37
103 #define LOM1_IDX_HOSTNAME6 0x38
104 #define LOM1_IDX_HOSTNAME7 0x39
105 #define LOM1_IDX_HOSTNAME8 0x3a
106 #define LOM1_IDX_HOSTNAME9 0x3b
107 #define LOM1_IDX_HOSTNAME10 0x3c
108 #define LOM1_IDX_HOSTNAME11 0x3d
109 #define LOM1_IDX_HOSTNAME12 0x3e
111 #define LOM2_IDX_HOSTNAMELEN 0x38
112 #define LOM2_IDX_HOSTNAME 0x39
114 #define LOM_IDX_CONFIG 0x5d
115 #define LOM_IDX_FAN1_CAL 0x5e
116 #define LOM_IDX_FAN2_CAL 0x5f
117 #define LOM_IDX_FAN3_CAL 0x60
118 #define LOM_IDX_FAN4_CAL 0x61
119 #define LOM_IDX_FAN1_LOW 0x62
120 #define LOM_IDX_FAN2_LOW 0x63
121 #define LOM_IDX_FAN3_LOW 0x64
122 #define LOM_IDX_FAN4_LOW 0x65
124 #define LOM_IDX_CONFIG2 0x66
125 #define LOM_IDX_CONFIG3 0x67
127 #define LOM_IDX_PROBE55 0x7e /* Always returns 0x55 */
128 #define LOM_IDX_PROBEAA 0x7f /* Always returns 0xaa */
130 #define LOM_IDX_WRITE 0x80
132 #define LOM_IDX4_TEMP_NAME_START 0x40
133 #define LOM_IDX4_TEMP_NAME_END 0xff
135 #define LOM_IDX5_FAN_NAME_START 0x40
136 #define LOM_IDX5_FAN_NAME_END 0xff
138 #define LOM_MAX_ALARM 4
139 #define LOM_MAX_FAN 4
140 #define LOM_MAX_PSU 3
141 #define LOM_MAX_TEMP 8
143 struct lom_cmd {
144 uint8_t lc_cmd;
145 uint8_t lc_data;
147 TAILQ_ENTRY(lom_cmd) lc_next;
150 struct lom_softc {
151 device_t sc_dev;
152 bus_space_tag_t sc_iot;
153 bus_space_handle_t sc_ioh;
155 int sc_type;
156 #define LOM_LOMLITE 0
157 #define LOM_LOMLITE2 2
158 int sc_space;
160 struct sysmon_envsys *sc_sme;
161 envsys_data_t sc_alarm[LOM_MAX_ALARM];
162 envsys_data_t sc_fan[LOM_MAX_FAN];
163 envsys_data_t sc_psu[LOM_MAX_PSU];
164 envsys_data_t sc_temp[LOM_MAX_TEMP];
166 int sc_num_alarm;
167 int sc_num_fan;
168 int sc_num_psu;
169 int sc_num_temp;
171 uint8_t sc_fan_cal[LOM_MAX_FAN];
172 uint8_t sc_fan_low[LOM_MAX_FAN];
174 char sc_hostname[MAXHOSTNAMELEN];
176 struct sysmon_wdog sc_smw;
177 int sc_wdog_period;
178 uint8_t sc_wdog_ctl;
179 struct lom_cmd sc_wdog_pat;
181 TAILQ_HEAD(, lom_cmd) sc_queue;
182 kmutex_t sc_queue_mtx;
183 struct callout sc_state_to;
184 int sc_state;
185 #define LOM_STATE_IDLE 0
186 #define LOM_STATE_CMD 1
187 #define LOM_STATE_DATA 2
188 int sc_retry;
191 static int lom_match(device_t, cfdata_t, void *);
192 static void lom_attach(device_t, device_t, void *);
194 CFATTACH_DECL_NEW(lom, sizeof(struct lom_softc),
195 lom_match, lom_attach, NULL, NULL);
197 static int lom_read(struct lom_softc *, uint8_t, uint8_t *);
198 static int lom_write(struct lom_softc *, uint8_t, uint8_t);
199 static void lom_queue_cmd(struct lom_softc *, struct lom_cmd *);
200 static void lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *);
201 static int lom1_read(struct lom_softc *, uint8_t, uint8_t *);
202 static int lom1_write(struct lom_softc *, uint8_t, uint8_t);
203 static int lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *);
204 static int lom1_write_polled(struct lom_softc *, uint8_t, uint8_t);
205 static void lom1_queue_cmd(struct lom_softc *, struct lom_cmd *);
206 static void lom1_process_queue(void *);
207 static void lom1_process_queue_locked(struct lom_softc *);
208 static int lom2_read(struct lom_softc *, uint8_t, uint8_t *);
209 static int lom2_write(struct lom_softc *, uint8_t, uint8_t);
210 static int lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *);
211 static int lom2_write_polled(struct lom_softc *, uint8_t, uint8_t);
212 static void lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);
213 static int lom2_intr(void *);
215 static int lom_init_desc(struct lom_softc *);
216 static void lom_refresh(struct sysmon_envsys *, envsys_data_t *);
217 static void lom1_write_hostname(struct lom_softc *);
218 static void lom2_write_hostname(struct lom_softc *);
220 static int lom_wdog_tickle(struct sysmon_wdog *);
221 static int lom_wdog_setmode(struct sysmon_wdog *);
223 static bool lom_shutdown(device_t, int);
225 static int
226 lom_match(device_t parent, cfdata_t match, void *aux)
228 struct ebus_attach_args *ea = aux;
230 if (strcmp(ea->ea_name, "SUNW,lom") == 0 ||
231 strcmp(ea->ea_name, "SUNW,lomh") == 0)
232 return (1);
234 return (0);
237 static void
238 lom_attach(device_t parent, device_t self, void *aux)
240 struct lom_softc *sc = device_private(self);
241 struct ebus_attach_args *ea = aux;
242 uint8_t reg, fw_rev, config, config2, config3;
243 uint8_t cal, low;
244 int i;
246 if (strcmp(ea->ea_name, "SUNW,lomh") == 0) {
247 if (ea->ea_nintr < 1) {
248 aprint_error(": no interrupt\n");
249 return;
251 sc->sc_type = LOM_LOMLITE2;
254 sc->sc_dev = self;
255 sc->sc_iot = ea->ea_bustag;
256 if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
257 ea->ea_reg[0].size, 0, &sc->sc_ioh) != 0) {
258 aprint_error(": can't map register space\n");
259 return;
262 if (sc->sc_type < LOM_LOMLITE2) {
263 /* XXX Magic */
264 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
265 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca);
268 if (lom_read(sc, LOM_IDX_PROBE55, &reg) || reg != 0x55 ||
269 lom_read(sc, LOM_IDX_PROBEAA, &reg) || reg != 0xaa ||
270 lom_read(sc, LOM_IDX_FW_REV, &fw_rev) ||
271 lom_read(sc, LOM_IDX_CONFIG, &config))
273 aprint_error(": not responding\n");
274 return;
277 aprint_normal(": %s: %s rev %d.%d\n", ea->ea_name,
278 sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2",
279 fw_rev >> 4, fw_rev & 0x0f);
281 TAILQ_INIT(&sc->sc_queue);
282 mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_BIO);
284 config2 = config3 = 0;
285 if (sc->sc_type < LOM_LOMLITE2) {
287 * LOMlite doesn't do interrupts so we limp along on
288 * timeouts.
290 callout_init(&sc->sc_state_to, 0);
291 callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc);
292 } else {
293 lom_read(sc, LOM_IDX_CONFIG2, &config2);
294 lom_read(sc, LOM_IDX_CONFIG3, &config3);
296 bus_intr_establish(sc->sc_iot, ea->ea_intr[0],
297 IPL_BIO, lom2_intr, sc);
300 sc->sc_num_alarm = LOM_MAX_ALARM;
301 sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN);
302 sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU);
303 sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP);
305 aprint_verbose_dev(self, "%d fan(s), %d PSU(s), %d temp sensor(s)\n",
306 sc->sc_num_fan, sc->sc_num_psu, sc->sc_num_temp);
308 for (i = 0; i < sc->sc_num_fan; i++) {
309 if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) ||
310 lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) {
311 aprint_error_dev(self, "can't read fan information\n");
312 return;
314 sc->sc_fan_cal[i] = cal;
315 sc->sc_fan_low[i] = low;
318 /* Initialize sensor data. */
319 sc->sc_sme = sysmon_envsys_create();
320 for (i = 0; i < sc->sc_num_alarm; i++) {
321 sc->sc_alarm[i].units = ENVSYS_INDICATOR;
322 snprintf(sc->sc_alarm[i].desc, sizeof(sc->sc_alarm[i].desc),
323 i == 0 ? "Fault LED" : "Alarm%d", i);
324 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_alarm[i])) {
325 sysmon_envsys_destroy(sc->sc_sme);
326 aprint_error_dev(self, "can't attach alarm sensor\n");
327 return;
330 for (i = 0; i < sc->sc_num_fan; i++) {
331 sc->sc_fan[i].units = ENVSYS_SFANRPM;
332 snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc),
333 "fan%d", i + 1);
334 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan[i])) {
335 sysmon_envsys_destroy(sc->sc_sme);
336 aprint_error_dev(self, "can't attach fan sensor\n");
337 return;
340 for (i = 0; i < sc->sc_num_psu; i++) {
341 sc->sc_psu[i].units = ENVSYS_INDICATOR;
342 snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc),
343 "PSU%d", i + 1);
344 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_psu[i])) {
345 sysmon_envsys_destroy(sc->sc_sme);
346 aprint_error_dev(self, "can't attach PSU sensor\n");
347 return;
350 for (i = 0; i < sc->sc_num_temp; i++) {
351 sc->sc_temp[i].units = ENVSYS_STEMP;
352 snprintf(sc->sc_temp[i].desc, sizeof(sc->sc_temp[i].desc),
353 "temp%d", i + 1);
354 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp[i])) {
355 sysmon_envsys_destroy(sc->sc_sme);
356 aprint_error_dev(self, "can't attach temp sensor\n");
357 return;
360 if (lom_init_desc(sc)) {
361 aprint_error_dev(self, "can't read sensor names\n");
362 sysmon_envsys_destroy(sc->sc_sme);
363 return;
366 sc->sc_sme->sme_name = device_xname(self);
367 sc->sc_sme->sme_cookie = sc;
368 sc->sc_sme->sme_refresh = lom_refresh;
369 if (sysmon_envsys_register(sc->sc_sme)) {
370 aprint_error_dev(self,
371 "unable to register envsys with sysmon\n");
372 sysmon_envsys_destroy(sc->sc_sme);
373 return;
376 /* Initialize watchdog. */
377 lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
378 lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl);
379 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET);
380 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
382 sc->sc_wdog_period = LOM_WDOG_TIME_MAX;
384 sc->sc_smw.smw_name = device_xname(self);
385 sc->sc_smw.smw_cookie = sc;
386 sc->sc_smw.smw_setmode = lom_wdog_setmode;
387 sc->sc_smw.smw_tickle = lom_wdog_tickle;
388 sc->sc_smw.smw_period = sc->sc_wdog_period;
389 if (sysmon_wdog_register(&sc->sc_smw)) {
390 aprint_error_dev(self,
391 "unable to register wdog with sysmon\n");
392 return;
395 aprint_verbose_dev(self, "Watchdog timer configured.\n");
397 if (!pmf_device_register1(self, NULL, NULL, lom_shutdown))
398 aprint_error_dev(self, "unable to register power handler\n");
401 static int
402 lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
404 if (sc->sc_type < LOM_LOMLITE2)
405 return lom1_read(sc, reg, val);
406 else
407 return lom2_read(sc, reg, val);
410 static int
411 lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
413 if (sc->sc_type < LOM_LOMLITE2)
414 return lom1_write(sc, reg, val);
415 else
416 return lom2_write(sc, reg, val);
419 static void
420 lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
422 if (sc->sc_type < LOM_LOMLITE2)
423 return lom1_queue_cmd(sc, lc);
424 else
425 return lom2_queue_cmd(sc, lc);
428 static void
429 lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
431 struct lom_cmd *lcp;
433 mutex_enter(&sc->sc_queue_mtx);
434 TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) {
435 if (lcp == lc) {
436 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
437 break;
440 mutex_exit(&sc->sc_queue_mtx);
443 static int
444 lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
446 struct lom_cmd lc;
447 int error;
449 if (cold)
450 return lom1_read_polled(sc, reg, val);
452 lc.lc_cmd = reg;
453 lc.lc_data = 0xff;
454 lom1_queue_cmd(sc, &lc);
456 error = tsleep(&lc, PZERO, "lomrd", hz);
457 if (error)
458 lom_dequeue_cmd(sc, &lc);
460 *val = lc.lc_data;
462 return (error);
465 static int
466 lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
468 struct lom_cmd lc;
469 int error;
471 if (cold)
472 return lom1_write_polled(sc, reg, val);
474 lc.lc_cmd = reg | LOM_IDX_WRITE;
475 lc.lc_data = val;
476 lom1_queue_cmd(sc, &lc);
478 error = tsleep(&lc, PZERO, "lomwr", 2 * hz);
479 if (error)
480 lom_dequeue_cmd(sc, &lc);
482 return (error);
485 static int
486 lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
488 uint8_t str;
489 int i;
491 /* Wait for input buffer to become available. */
492 for (i = 30; i > 0; i--) {
493 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
494 delay(1000);
495 if ((str & LOM1_STATUS_BUSY) == 0)
496 break;
498 if (i == 0)
499 return (ETIMEDOUT);
501 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
503 /* Wait until the microcontroller fills output buffer. */
504 for (i = 30; i > 0; i--) {
505 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
506 delay(1000);
507 if ((str & LOM1_STATUS_BUSY) == 0)
508 break;
510 if (i == 0)
511 return (ETIMEDOUT);
513 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
514 return (0);
517 static int
518 lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
520 uint8_t str;
521 int i;
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;
530 if (i == 0)
531 return (ETIMEDOUT);
533 reg |= LOM_IDX_WRITE;
534 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
536 /* Wait until the microcontroller fills output buffer. */
537 for (i = 30; i > 0; i--) {
538 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
539 delay(1000);
540 if ((str & LOM1_STATUS_BUSY) == 0)
541 break;
543 if (i == 0)
544 return (ETIMEDOUT);
546 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val);
548 return (0);
551 static void
552 lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
554 mutex_enter(&sc->sc_queue_mtx);
555 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
556 if (sc->sc_state == LOM_STATE_IDLE) {
557 sc->sc_state = LOM_STATE_CMD;
558 lom1_process_queue_locked(sc);
560 mutex_exit(&sc->sc_queue_mtx);
563 static void
564 lom1_process_queue(void *arg)
566 struct lom_softc *sc = arg;
568 mutex_enter(&sc->sc_queue_mtx);
569 lom1_process_queue_locked(sc);
570 mutex_exit(&sc->sc_queue_mtx);
573 static void
574 lom1_process_queue_locked(struct lom_softc *sc)
576 struct lom_cmd *lc;
577 uint8_t str;
579 lc = TAILQ_FIRST(&sc->sc_queue);
580 if (lc == NULL) {
581 sc->sc_state = LOM_STATE_IDLE;
582 return;
585 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
586 if (str & LOM1_STATUS_BUSY) {
587 if (sc->sc_retry++ < 30) {
588 callout_schedule(&sc->sc_state_to, mstohz(1));
589 return;
593 * Looks like the microcontroller got wedged. Unwedge
594 * it by writing this magic value. Give it some time
595 * to recover.
597 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac);
598 callout_schedule(&sc->sc_state_to, mstohz(1000));
599 sc->sc_state = LOM_STATE_CMD;
600 return;
603 sc->sc_retry = 0;
605 if (sc->sc_state == LOM_STATE_CMD) {
606 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd);
607 sc->sc_state = LOM_STATE_DATA;
608 callout_schedule(&sc->sc_state_to, mstohz(250));
609 return;
612 KASSERT(sc->sc_state == LOM_STATE_DATA);
613 if ((lc->lc_cmd & LOM_IDX_WRITE) == 0)
614 lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
615 else
616 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data);
618 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
620 wakeup(lc);
622 if (!TAILQ_EMPTY(&sc->sc_queue)) {
623 sc->sc_state = LOM_STATE_CMD;
624 callout_schedule(&sc->sc_state_to, mstohz(1));
625 return;
628 sc->sc_state = LOM_STATE_IDLE;
631 static int
632 lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
634 struct lom_cmd lc;
635 int error;
637 if (cold)
638 return lom2_read_polled(sc, reg, val);
640 lc.lc_cmd = reg;
641 lc.lc_data = 0xff;
642 lom2_queue_cmd(sc, &lc);
644 error = tsleep(&lc, PZERO, "lom2rd", hz);
645 if (error)
646 lom_dequeue_cmd(sc, &lc);
648 *val = lc.lc_data;
650 return (error);
653 static int
654 lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
656 uint8_t str;
657 int i;
659 /* Wait for input buffer to become available. */
660 for (i = 1000; i > 0; i--) {
661 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
662 delay(10);
663 if ((str & LOM2_STATUS_IBF) == 0)
664 break;
666 if (i == 0)
667 return (ETIMEDOUT);
669 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
671 /* Wait until the microcontroller fills output buffer. */
672 for (i = 1000; i > 0; i--) {
673 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
674 delay(10);
675 if (str & LOM2_STATUS_OBF)
676 break;
678 if (i == 0)
679 return (ETIMEDOUT);
681 *val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
682 return (0);
685 static int
686 lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
688 struct lom_cmd lc;
689 int error;
691 if (cold)
692 return lom2_write_polled(sc, reg, val);
694 lc.lc_cmd = reg | LOM_IDX_WRITE;
695 lc.lc_data = val;
696 lom2_queue_cmd(sc, &lc);
698 error = tsleep(&lc, PZERO, "lom2wr", hz);
699 if (error)
700 lom_dequeue_cmd(sc, &lc);
702 return (error);
705 static int
706 lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
708 uint8_t str;
709 int i;
711 /* Wait for input buffer to become available. */
712 for (i = 1000; i > 0; i--) {
713 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
714 delay(10);
715 if ((str & LOM2_STATUS_IBF) == 0)
716 break;
718 if (i == 0)
719 return (ETIMEDOUT);
721 if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
722 reg |= LOM_IDX_WRITE;
724 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
726 /* Wait until the microcontroller fills output buffer. */
727 for (i = 1000; i > 0; i--) {
728 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
729 delay(10);
730 if (str & LOM2_STATUS_OBF)
731 break;
733 if (i == 0)
734 return (ETIMEDOUT);
736 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
738 /* Wait for input buffer to become available. */
739 for (i = 1000; i > 0; i--) {
740 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
741 delay(10);
742 if ((str & LOM2_STATUS_IBF) == 0)
743 break;
745 if (i == 0)
746 return (ETIMEDOUT);
748 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val);
750 /* Wait until the microcontroller fills output buffer. */
751 for (i = 1000; i > 0; i--) {
752 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
753 delay(10);
754 if (str & LOM2_STATUS_OBF)
755 break;
757 if (i == 0)
758 return (ETIMEDOUT);
760 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
762 /* If we switched spaces, remember the one we're in now. */
763 if (reg == LOM_IDX_CMD)
764 sc->sc_space = val;
766 return (0);
769 static void
770 lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
772 uint8_t str;
774 mutex_enter(&sc->sc_queue_mtx);
775 TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
776 if (sc->sc_state == LOM_STATE_IDLE) {
777 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
778 if ((str & LOM2_STATUS_IBF) == 0) {
779 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
780 LOM2_CMD, lc->lc_cmd);
781 sc->sc_state = LOM_STATE_DATA;
784 mutex_exit(&sc->sc_queue_mtx);
787 static int
788 lom2_intr(void *arg)
790 struct lom_softc *sc = arg;
791 struct lom_cmd *lc;
792 uint8_t str, obr;
794 mutex_enter(&sc->sc_queue_mtx);
796 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
797 obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
799 lc = TAILQ_FIRST(&sc->sc_queue);
800 if (lc == NULL) {
801 mutex_exit(&sc->sc_queue_mtx);
802 return (0);
805 if (lc->lc_cmd & LOM_IDX_WRITE) {
806 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
807 LOM2_DATA, lc->lc_data);
808 lc->lc_cmd &= ~LOM_IDX_WRITE;
809 mutex_exit(&sc->sc_queue_mtx);
810 return (1);
813 KASSERT(sc->sc_state = LOM_STATE_DATA);
814 lc->lc_data = obr;
816 TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
818 wakeup(lc);
820 sc->sc_state = LOM_STATE_IDLE;
822 if (!TAILQ_EMPTY(&sc->sc_queue)) {
823 str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
824 if ((str & LOM2_STATUS_IBF) == 0) {
825 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
826 LOM2_CMD, lc->lc_cmd);
827 sc->sc_state = LOM_STATE_DATA;
831 mutex_exit(&sc->sc_queue_mtx);
833 return (1);
836 static int
837 lom_init_desc(struct lom_softc *sc)
839 uint8_t val;
840 int i, j, k;
841 int error;
843 /* LOMlite doesn't provide sensor descriptions. */
844 if (sc->sc_type < LOM_LOMLITE2)
845 return (0);
848 * Read temperature sensor names.
850 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP);
851 if (error)
852 return (error);
854 i = 0;
855 j = 0;
856 k = LOM_IDX4_TEMP_NAME_START;
857 while (k <= LOM_IDX4_TEMP_NAME_END) {
858 error = lom_read(sc, k++, &val);
859 if (error)
860 goto fail;
862 if (val == 0xff)
863 break;
865 if (j < sizeof (sc->sc_temp[i].desc) - 1)
866 sc->sc_temp[i].desc[j++] = val;
868 if (val == '\0') {
869 i++;
870 j = 0;
871 if (i < sc->sc_num_temp)
872 continue;
874 break;
879 * Read fan names.
881 error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN);
882 if (error)
883 return (error);
885 i = 0;
886 j = 0;
887 k = LOM_IDX5_FAN_NAME_START;
888 while (k <= LOM_IDX5_FAN_NAME_END) {
889 error = lom_read(sc, k++, &val);
890 if (error)
891 goto fail;
893 if (val == 0xff)
894 break;
896 if (j < sizeof (sc->sc_fan[i].desc) - 1)
897 sc->sc_fan[i].desc[j++] = val;
899 if (val == '\0') {
900 i++;
901 j = 0;
902 if (i < sc->sc_num_fan)
903 continue;
905 break;
909 fail:
910 lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC);
911 return (error);
914 static void
915 lom_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
917 struct lom_softc *sc = sme->sme_cookie;
918 uint8_t val;
919 int i;
921 if (lom_read(sc, LOM_IDX_ALARM, &val)) {
922 for (i = 0; i < sc->sc_num_alarm; i++)
923 sc->sc_alarm[i].state = ENVSYS_SINVALID;
924 } else {
925 /* Fault LED */
926 if ((val & LOM_ALARM_FAULT) == LOM_ALARM_FAULT)
927 sc->sc_alarm[0].value_cur = 0;
928 else
929 sc->sc_alarm[0].value_cur = 1;
930 sc->sc_alarm[0].state = ENVSYS_SVALID;
932 /* Alarms */
933 for (i = 1; i < sc->sc_num_alarm; i++) {
934 if ((val & (LOM_ALARM_1 << (i - 1))) == 0)
935 sc->sc_alarm[i].value_cur = 0;
936 else
937 sc->sc_alarm[i].value_cur = 1;
938 sc->sc_alarm[i].state = ENVSYS_SVALID;
942 for (i = 0; i < sc->sc_num_fan; i++) {
943 if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) {
944 sc->sc_fan[i].state = ENVSYS_SINVALID;
945 continue;
948 sc->sc_fan[i].value_cur = (60 * sc->sc_fan_cal[i] * val) / 100;
949 if (val < sc->sc_fan_low[i])
950 sc->sc_fan[i].state = ENVSYS_SCRITICAL;
951 else
952 sc->sc_fan[i].state = ENVSYS_SVALID;
955 for (i = 0; i < sc->sc_num_psu; i++) {
956 if (lom_read(sc, LOM_IDX_PSU1 + i, &val) ||
957 !ISSET(val, LOM_PSU_PRESENT)) {
958 sc->sc_psu[i].state = ENVSYS_SINVALID;
959 continue;
962 if (val & LOM_PSU_STANDBY) {
963 sc->sc_psu[i].value_cur = 0;
964 sc->sc_psu[i].state = ENVSYS_SVALID;
965 } else {
966 sc->sc_psu[i].value_cur = 1;
967 if (ISSET(val, LOM_PSU_INPUTA) &&
968 ISSET(val, LOM_PSU_INPUTB) &&
969 ISSET(val, LOM_PSU_OUTPUT))
970 sc->sc_psu[i].state = ENVSYS_SVALID;
971 else
972 sc->sc_psu[i].state = ENVSYS_SCRITICAL;
976 for (i = 0; i < sc->sc_num_temp; i++) {
977 if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) {
978 sc->sc_temp[i].state = ENVSYS_SINVALID;
979 continue;
982 sc->sc_temp[i].value_cur = val * 1000000 + 273150000;
983 sc->sc_temp[i].state = ENVSYS_SVALID;
987 * If our hostname is set and differs from what's stored in
988 * the LOM, write the new hostname back to the LOM. Note that
989 * we include the terminating NUL when writing the hostname
990 * back to the LOM, otherwise the LOM will print any trailing
991 * garbage.
993 if (hostnamelen > 0 &&
994 strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) {
995 if (sc->sc_type < LOM_LOMLITE2)
996 lom1_write_hostname(sc);
997 else
998 lom2_write_hostname(sc);
999 strlcpy(sc->sc_hostname, hostname, sizeof(hostname));
1003 static void
1004 lom1_write_hostname(struct lom_softc *sc)
1006 char name[LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1];
1007 char *p;
1008 int i;
1011 * LOMlite generally doesn't have enough space to store the
1012 * fully qualified hostname. If the hostname is too long,
1013 * strip off the domain name.
1015 strlcpy(name, hostname, sizeof(name));
1016 if (hostnamelen > sizeof(name)) {
1017 p = strchr(name, '.');
1018 if (p)
1019 *p = '\0';
1022 for (i = 0; i < strlen(name) + 1; i++)
1023 if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i]))
1024 break;
1027 static void
1028 lom2_write_hostname(struct lom_softc *sc)
1030 int i;
1032 lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1);
1033 for (i = 0; i < hostnamelen + 1; i++)
1034 lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]);
1037 static int
1038 lom_wdog_tickle(struct sysmon_wdog *smw)
1040 struct lom_softc *sc = smw->smw_cookie;
1042 /* Pat the dog. */
1043 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
1044 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
1045 lom_queue_cmd(sc, &sc->sc_wdog_pat);
1047 return 0;
1050 static int
1051 lom_wdog_setmode(struct sysmon_wdog *smw)
1053 struct lom_softc *sc = smw->smw_cookie;
1055 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
1056 /* disable watchdog */
1057 sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET);
1058 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1059 } else {
1060 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
1061 smw->smw_period = sc->sc_wdog_period;
1062 else if (smw->smw_period == 0 ||
1063 smw->smw_period > LOM_WDOG_TIME_MAX)
1064 return EINVAL;
1065 lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period);
1067 /* enable watchdog */
1068 lom_dequeue_cmd(sc, &sc->sc_wdog_pat);
1069 sc->sc_wdog_ctl |= LOM_WDOG_ENABLE|LOM_WDOG_RESET;
1070 sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
1071 sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
1072 lom_queue_cmd(sc, &sc->sc_wdog_pat);
1075 return 0;
1078 static bool
1079 lom_shutdown(device_t dev, int how)
1081 struct lom_softc *sc = device_private(dev);
1083 sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE;
1084 lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1085 return true;