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 $ */
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>
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
147 TAILQ_ENTRY(lom_cmd
) lc_next
;
152 bus_space_tag_t sc_iot
;
153 bus_space_handle_t sc_ioh
;
156 #define LOM_LOMLITE 0
157 #define LOM_LOMLITE2 2
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
];
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
;
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
;
185 #define LOM_STATE_IDLE 0
186 #define LOM_STATE_CMD 1
187 #define LOM_STATE_DATA 2
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);
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)
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
;
246 if (strcmp(ea
->ea_name
, "SUNW,lomh") == 0) {
247 if (ea
->ea_nintr
< 1) {
248 aprint_error(": no interrupt\n");
251 sc
->sc_type
= LOM_LOMLITE2
;
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");
262 if (sc
->sc_type
< LOM_LOMLITE2
) {
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
!= 0x55 ||
269 lom_read(sc
, LOM_IDX_PROBEAA
, ®
) || 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");
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
290 callout_init(&sc
->sc_state_to
, 0);
291 callout_setfunc(&sc
->sc_state_to
, lom1_process_queue
, sc
);
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");
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");
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
),
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");
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
),
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");
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
),
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");
360 if (lom_init_desc(sc
)) {
361 aprint_error_dev(self
, "can't read sensor names\n");
362 sysmon_envsys_destroy(sc
->sc_sme
);
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
);
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");
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");
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
);
407 return lom2_read(sc
, reg
, val
);
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
);
416 return lom2_write(sc
, reg
, val
);
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
);
425 return lom2_queue_cmd(sc
, lc
);
429 lom_dequeue_cmd(struct lom_softc
*sc
, struct lom_cmd
*lc
)
433 mutex_enter(&sc
->sc_queue_mtx
);
434 TAILQ_FOREACH(lcp
, &sc
->sc_queue
, lc_next
) {
436 TAILQ_REMOVE(&sc
->sc_queue
, lc
, lc_next
);
440 mutex_exit(&sc
->sc_queue_mtx
);
444 lom1_read(struct lom_softc
*sc
, uint8_t reg
, uint8_t *val
)
450 return lom1_read_polled(sc
, reg
, val
);
454 lom1_queue_cmd(sc
, &lc
);
456 error
= tsleep(&lc
, PZERO
, "lomrd", hz
);
458 lom_dequeue_cmd(sc
, &lc
);
466 lom1_write(struct lom_softc
*sc
, uint8_t reg
, uint8_t val
)
472 return lom1_write_polled(sc
, reg
, val
);
474 lc
.lc_cmd
= reg
| LOM_IDX_WRITE
;
476 lom1_queue_cmd(sc
, &lc
);
478 error
= tsleep(&lc
, PZERO
, "lomwr", 2 * hz
);
480 lom_dequeue_cmd(sc
, &lc
);
486 lom1_read_polled(struct lom_softc
*sc
, uint8_t reg
, uint8_t *val
)
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
);
495 if ((str
& LOM1_STATUS_BUSY
) == 0)
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
);
507 if ((str
& LOM1_STATUS_BUSY
) == 0)
513 *val
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, LOM1_DATA
);
518 lom1_write_polled(struct lom_softc
*sc
, uint8_t reg
, uint8_t val
)
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
);
527 if ((str
& LOM1_STATUS_BUSY
) == 0)
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
);
540 if ((str
& LOM1_STATUS_BUSY
) == 0)
546 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, LOM1_DATA
, val
);
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
);
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
);
574 lom1_process_queue_locked(struct lom_softc
*sc
)
579 lc
= TAILQ_FIRST(&sc
->sc_queue
);
581 sc
->sc_state
= LOM_STATE_IDLE
;
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));
593 * Looks like the microcontroller got wedged. Unwedge
594 * it by writing this magic value. Give it some time
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
;
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));
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
);
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
);
622 if (!TAILQ_EMPTY(&sc
->sc_queue
)) {
623 sc
->sc_state
= LOM_STATE_CMD
;
624 callout_schedule(&sc
->sc_state_to
, mstohz(1));
628 sc
->sc_state
= LOM_STATE_IDLE
;
632 lom2_read(struct lom_softc
*sc
, uint8_t reg
, uint8_t *val
)
638 return lom2_read_polled(sc
, reg
, val
);
642 lom2_queue_cmd(sc
, &lc
);
644 error
= tsleep(&lc
, PZERO
, "lom2rd", hz
);
646 lom_dequeue_cmd(sc
, &lc
);
654 lom2_read_polled(struct lom_softc
*sc
, uint8_t reg
, uint8_t *val
)
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
);
663 if ((str
& LOM2_STATUS_IBF
) == 0)
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
);
675 if (str
& LOM2_STATUS_OBF
)
681 *val
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, LOM2_DATA
);
686 lom2_write(struct lom_softc
*sc
, uint8_t reg
, uint8_t val
)
692 return lom2_write_polled(sc
, reg
, val
);
694 lc
.lc_cmd
= reg
| LOM_IDX_WRITE
;
696 lom2_queue_cmd(sc
, &lc
);
698 error
= tsleep(&lc
, PZERO
, "lom2wr", hz
);
700 lom_dequeue_cmd(sc
, &lc
);
706 lom2_write_polled(struct lom_softc
*sc
, uint8_t reg
, uint8_t val
)
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
);
715 if ((str
& LOM2_STATUS_IBF
) == 0)
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
);
730 if (str
& LOM2_STATUS_OBF
)
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
);
742 if ((str
& LOM2_STATUS_IBF
) == 0)
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
);
754 if (str
& LOM2_STATUS_OBF
)
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
)
770 lom2_queue_cmd(struct lom_softc
*sc
, struct lom_cmd
*lc
)
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
);
790 struct lom_softc
*sc
= arg
;
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
);
801 mutex_exit(&sc
->sc_queue_mtx
);
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
);
813 KASSERT(sc
->sc_state
= LOM_STATE_DATA
);
816 TAILQ_REMOVE(&sc
->sc_queue
, lc
, lc_next
);
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
);
837 lom_init_desc(struct lom_softc
*sc
)
843 /* LOMlite doesn't provide sensor descriptions. */
844 if (sc
->sc_type
< LOM_LOMLITE2
)
848 * Read temperature sensor names.
850 error
= lom_write(sc
, LOM_IDX_CMD
, LOM_IDX_CMD_TEMP
);
856 k
= LOM_IDX4_TEMP_NAME_START
;
857 while (k
<= LOM_IDX4_TEMP_NAME_END
) {
858 error
= lom_read(sc
, k
++, &val
);
865 if (j
< sizeof (sc
->sc_temp
[i
].desc
) - 1)
866 sc
->sc_temp
[i
].desc
[j
++] = val
;
871 if (i
< sc
->sc_num_temp
)
881 error
= lom_write(sc
, LOM_IDX_CMD
, LOM_IDX_CMD_FAN
);
887 k
= LOM_IDX5_FAN_NAME_START
;
888 while (k
<= LOM_IDX5_FAN_NAME_END
) {
889 error
= lom_read(sc
, k
++, &val
);
896 if (j
< sizeof (sc
->sc_fan
[i
].desc
) - 1)
897 sc
->sc_fan
[i
].desc
[j
++] = val
;
902 if (i
< sc
->sc_num_fan
)
910 lom_write(sc
, LOM_IDX_CMD
, LOM_IDX_CMD_GENERIC
);
915 lom_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
917 struct lom_softc
*sc
= sme
->sme_cookie
;
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
;
926 if ((val
& LOM_ALARM_FAULT
) == LOM_ALARM_FAULT
)
927 sc
->sc_alarm
[0].value_cur
= 0;
929 sc
->sc_alarm
[0].value_cur
= 1;
930 sc
->sc_alarm
[0].state
= ENVSYS_SVALID
;
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;
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
;
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
;
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
;
962 if (val
& LOM_PSU_STANDBY
) {
963 sc
->sc_psu
[i
].value_cur
= 0;
964 sc
->sc_psu
[i
].state
= ENVSYS_SVALID
;
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
;
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
;
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
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
);
998 lom2_write_hostname(sc
);
999 strlcpy(sc
->sc_hostname
, hostname
, sizeof(hostname
));
1004 lom1_write_hostname(struct lom_softc
*sc
)
1006 char name
[LOM1_IDX_HOSTNAME12
- LOM1_IDX_HOSTNAME1
+ 1];
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
, '.');
1022 for (i
= 0; i
< strlen(name
) + 1; i
++)
1023 if (lom_write(sc
, LOM1_IDX_HOSTNAME1
+ i
, name
[i
]))
1028 lom2_write_hostname(struct lom_softc
*sc
)
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
]);
1038 lom_wdog_tickle(struct sysmon_wdog
*smw
)
1040 struct lom_softc
*sc
= smw
->smw_cookie
;
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
);
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
);
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
)
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
);
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
);