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