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