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