xref: /openbsd/sys/arch/sparc64/dev/lom.c (revision 50dbebda)
1 /*	$OpenBSD: lom.c,v 1.29 2022/07/04 19:06:10 miod Exp $	*/
2 /*
3  * Copyright (c) 2009 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/kernel.h>
21 #include <sys/proc.h>
22 #include <sys/sensors.h>
23 #include <sys/systm.h>
24 #include <sys/timeout.h>
25 
26 #include <machine/autoconf.h>
27 #include <machine/openfirm.h>
28 
29 #include <sparc64/dev/ebusreg.h>
30 #include <sparc64/dev/ebusvar.h>
31 
32 /*
33  * LOMlite is a so far unidentified microcontroller.
34  */
35 #define LOM1_STATUS		0x00	/* R */
36 #define  LOM1_STATUS_BUSY	0x80
37 #define LOM1_CMD		0x00	/* W */
38 #define LOM1_DATA		0x01	/* R/W */
39 
40 /*
41  * LOMlite2 is implemented as a H8/3437 microcontroller which has its
42  * on-chip host interface hooked up to EBus.
43  */
44 #define LOM2_DATA		0x00	/* R/W */
45 #define LOM2_CMD		0x01	/* W */
46 #define LOM2_STATUS		0x01	/* R */
47 #define  LOM2_STATUS_OBF	0x01	/* Output Buffer Full */
48 #define  LOM2_STATUS_IBF	0x02	/* Input Buffer Full  */
49 
50 #define LOM_IDX_CMD		0x00
51 #define  LOM_IDX_CMD_GENERIC	0x00
52 #define  LOM_IDX_CMD_TEMP	0x04
53 #define  LOM_IDX_CMD_FAN	0x05
54 
55 #define LOM_IDX_FW_REV		0x01	/* Firmware revision  */
56 
57 #define LOM_IDX_FAN1		0x04	/* Fan speed */
58 #define LOM_IDX_FAN2		0x05
59 #define LOM_IDX_FAN3		0x06
60 #define LOM_IDX_FAN4		0x07
61 #define LOM_IDX_PSU1		0x08	/* PSU status */
62 #define LOM_IDX_PSU2		0x09
63 #define LOM_IDX_PSU3		0x0a
64 #define  LOM_PSU_INPUTA		0x01
65 #define  LOM_PSU_INPUTB		0x02
66 #define  LOM_PSU_OUTPUT		0x04
67 #define  LOM_PSU_PRESENT	0x08
68 #define  LOM_PSU_STANDBY	0x10
69 
70 #define LOM_IDX_TEMP1		0x18	/* Temperature */
71 #define LOM_IDX_TEMP2		0x19
72 #define LOM_IDX_TEMP3		0x1a
73 #define LOM_IDX_TEMP4		0x1b
74 #define LOM_IDX_TEMP5		0x1c
75 #define LOM_IDX_TEMP6		0x1d
76 #define LOM_IDX_TEMP7		0x1e
77 #define LOM_IDX_TEMP8		0x1f
78 
79 #define LOM_IDX_LED1		0x25
80 
81 #define LOM_IDX_ALARM		0x30
82 #define LOM_IDX_WDOG_CTL	0x31
83 #define  LOM_WDOG_ENABLE	0x01
84 #define  LOM_WDOG_RESET		0x02
85 #define  LOM_WDOG_AL3_WDOG	0x04
86 #define  LOM_WDOG_AL3_FANPSU	0x08
87 #define LOM_IDX_WDOG_TIME	0x32
88 #define  LOM_WDOG_TIME_MAX	126
89 
90 #define LOM1_IDX_HOSTNAME1	0x33
91 #define LOM1_IDX_HOSTNAME2	0x34
92 #define LOM1_IDX_HOSTNAME3	0x35
93 #define LOM1_IDX_HOSTNAME4	0x36
94 #define LOM1_IDX_HOSTNAME5	0x37
95 #define LOM1_IDX_HOSTNAME6	0x38
96 #define LOM1_IDX_HOSTNAME7	0x39
97 #define LOM1_IDX_HOSTNAME8	0x3a
98 #define LOM1_IDX_HOSTNAME9	0x3b
99 #define LOM1_IDX_HOSTNAME10	0x3c
100 #define LOM1_IDX_HOSTNAME11	0x3d
101 #define LOM1_IDX_HOSTNAME12	0x3e
102 
103 #define LOM2_IDX_HOSTNAMELEN	0x38
104 #define LOM2_IDX_HOSTNAME	0x39
105 
106 #define LOM_IDX_CONFIG		0x5d
107 #define LOM_IDX_FAN1_CAL	0x5e
108 #define LOM_IDX_FAN2_CAL	0x5f
109 #define LOM_IDX_FAN3_CAL	0x60
110 #define LOM_IDX_FAN4_CAL	0x61
111 #define LOM_IDX_FAN1_LOW	0x62
112 #define LOM_IDX_FAN2_LOW	0x63
113 #define LOM_IDX_FAN3_LOW	0x64
114 #define LOM_IDX_FAN4_LOW	0x65
115 
116 #define LOM_IDX_CONFIG2		0x66
117 #define LOM_IDX_CONFIG3		0x67
118 
119 #define LOM_IDX_PROBE55		0x7e	/* Always returns 0x55 */
120 #define LOM_IDX_PROBEAA		0x7f	/* Always returns 0xaa */
121 
122 #define LOM_IDX_WRITE		0x80
123 
124 #define LOM_IDX4_TEMP_NAME_START	0x40
125 #define LOM_IDX4_TEMP_NAME_END		0xff
126 
127 #define LOM_IDX5_FAN_NAME_START		0x40
128 #define LOM_IDX5_FAN_NAME_END		0xff
129 
130 #define LOM_MAX_FAN	4
131 #define LOM_MAX_PSU	3
132 #define LOM_MAX_TEMP	8
133 
134 struct lom_cmd {
135 	uint8_t			lc_cmd;
136 	uint8_t			lc_data;
137 
138 	TAILQ_ENTRY(lom_cmd)	lc_next;
139 };
140 
141 struct lom_softc {
142 	struct device		sc_dev;
143 	bus_space_tag_t		sc_iot;
144 	bus_space_handle_t	sc_ioh;
145 
146 	int			sc_type;
147 #define LOM_LOMLITE		0
148 #define LOM_LOMLITE2		2
149 	int			sc_space;
150 
151 	struct ksensor		sc_fan[LOM_MAX_FAN];
152 	struct ksensor		sc_psu[LOM_MAX_PSU];
153 	struct ksensor		sc_temp[LOM_MAX_TEMP];
154 	struct ksensordev	sc_sensordev;
155 
156 	int			sc_num_fan;
157 	int			sc_num_psu;
158 	int			sc_num_temp;
159 
160 	uint8_t			sc_fan_cal[LOM_MAX_FAN];
161 	uint8_t			sc_fan_low[LOM_MAX_FAN];
162 
163 	char			sc_hostname[MAXHOSTNAMELEN];
164 
165 	struct timeout		sc_wdog_to;
166 	int			sc_wdog_period;
167 	uint8_t			sc_wdog_ctl;
168 	struct lom_cmd		sc_wdog_pat;
169 
170 	TAILQ_HEAD(, lom_cmd)	sc_queue;
171 	struct mutex		sc_queue_mtx;
172 	struct timeout		sc_state_to;
173 	int			sc_state;
174 #define LOM_STATE_IDLE		0
175 #define LOM_STATE_CMD		1
176 #define LOM_STATE_DATA		2
177 	int			sc_retry;
178 };
179 
180 int	lom_match(struct device *, void *, void *);
181 void	lom_attach(struct device *, struct device *, void *);
182 int	lom_activate(struct device *, int);
183 
184 const struct cfattach lom_ca = {
185 	sizeof(struct lom_softc), lom_match, lom_attach,
186 	NULL, lom_activate
187 };
188 
189 struct cfdriver lom_cd = {
190 	NULL, "lom", DV_DULL
191 };
192 
193 int	lom_read(struct lom_softc *, uint8_t, uint8_t *);
194 int	lom_write(struct lom_softc *, uint8_t, uint8_t);
195 void	lom_queue_cmd(struct lom_softc *, struct lom_cmd *);
196 void	lom_dequeue_cmd(struct lom_softc *, struct lom_cmd *);
197 int	lom1_read(struct lom_softc *, uint8_t, uint8_t *);
198 int	lom1_write(struct lom_softc *, uint8_t, uint8_t);
199 int	lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *);
200 int	lom1_write_polled(struct lom_softc *, uint8_t, uint8_t);
201 void	lom1_queue_cmd(struct lom_softc *, struct lom_cmd *);
202 void	lom1_process_queue(void *);
203 void	lom1_process_queue_locked(struct lom_softc *);
204 int	lom2_read(struct lom_softc *, uint8_t, uint8_t *);
205 int	lom2_write(struct lom_softc *, uint8_t, uint8_t);
206 int	lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *);
207 int	lom2_write_polled(struct lom_softc *, uint8_t, uint8_t);
208 void	lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);
209 int	lom2_intr(void *);
210 
211 int	lom_init_desc(struct lom_softc *sc);
212 void	lom_refresh(void *);
213 void	lom1_write_hostname(struct lom_softc *);
214 void	lom2_write_hostname(struct lom_softc *);
215 
216 void	lom_wdog_pat(void *);
217 int	lom_wdog_cb(void *, int);
218 
219 void	lom_shutdown(void *);
220 
221 int
lom_match(struct device * parent,void * match,void * aux)222 lom_match(struct device *parent, void *match, void *aux)
223 {
224 	struct ebus_attach_args *ea = aux;
225 
226 	if (strcmp(ea->ea_name, "SUNW,lom") == 0 ||
227 	    strcmp(ea->ea_name, "SUNW,lomh") == 0)
228 		return (1);
229 
230 	return (0);
231 }
232 
233 void
lom_attach(struct device * parent,struct device * self,void * aux)234 lom_attach(struct device *parent, struct device *self, void *aux)
235 {
236 	struct lom_softc *sc = (void *)self;
237 	struct ebus_attach_args *ea = aux;
238 	uint8_t reg, fw_rev, config, config2, config3;
239 	uint8_t cal, low;
240 	int i;
241 
242 	if (strcmp(ea->ea_name, "SUNW,lomh") == 0) {
243 		if (ea->ea_nintrs < 1) {
244 			printf(": no interrupt\n");
245 			return;
246 		}
247 		sc->sc_type = LOM_LOMLITE2;
248 	}
249 
250 	if (ebus_bus_map(ea->ea_iotag, 0,
251 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
252 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
253 		sc->sc_iot = ea->ea_iotag;
254 	} else if (ebus_bus_map(ea->ea_memtag, 0,
255 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
256 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
257 		sc->sc_iot = ea->ea_memtag;
258 	} else {
259 		printf(": can't map register space\n");
260                 return;
261 	}
262 
263 	if (sc->sc_type < LOM_LOMLITE2) {
264 		/* XXX Magic */
265 		bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
266 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca);
267 	}
268 
269 	if (lom_read(sc, LOM_IDX_PROBE55, &reg) || reg != 0x55 ||
270 	    lom_read(sc, LOM_IDX_PROBEAA, &reg) || reg != 0xaa ||
271 	    lom_read(sc, LOM_IDX_FW_REV, &fw_rev) ||
272 	    lom_read(sc, LOM_IDX_CONFIG, &config))
273 	{
274 		printf(": not responding\n");
275 		return;
276 	}
277 
278 	TAILQ_INIT(&sc->sc_queue);
279 	mtx_init(&sc->sc_queue_mtx, IPL_BIO);
280 
281 	config2 = config3 = 0;
282 	if (sc->sc_type < LOM_LOMLITE2) {
283 		/*
284 		 * LOMlite doesn't do interrupts so we limp along on
285 		 * timeouts.
286 		 */
287 		timeout_set(&sc->sc_state_to, lom1_process_queue, sc);
288 	} else {
289 		lom_read(sc, LOM_IDX_CONFIG2, &config2);
290 		lom_read(sc, LOM_IDX_CONFIG3, &config3);
291 
292 		bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
293 		    IPL_BIO, 0, lom2_intr, sc, self->dv_xname);
294 	}
295 
296 	sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN);
297 	sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU);
298 	sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP);
299 
300 	for (i = 0; i < sc->sc_num_fan; i++) {
301 		if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) ||
302 		    lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) {
303 			printf(": can't read fan information\n");
304 			return;
305 		}
306 		sc->sc_fan_cal[i] = cal;
307 		sc->sc_fan_low[i] = low;
308 	}
309 
310 	/* Initialize sensor data. */
311 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
312 	    sizeof(sc->sc_sensordev.xname));
313 	for (i = 0; i < sc->sc_num_fan; i++) {
314 		sc->sc_fan[i].type = SENSOR_FANRPM;
315 		sensor_attach(&sc->sc_sensordev, &sc->sc_fan[i]);
316 		snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc),
317 		    "fan%d", i + 1);
318 	}
319 	for (i = 0; i < sc->sc_num_psu; i++) {
320 		sc->sc_psu[i].type = SENSOR_INDICATOR;
321 		sensor_attach(&sc->sc_sensordev, &sc->sc_psu[i]);
322 		snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc),
323 		    "PSU%d", i + 1);
324 	}
325 	for (i = 0; i < sc->sc_num_temp; i++) {
326 		sc->sc_temp[i].type = SENSOR_TEMP;
327 		sensor_attach(&sc->sc_sensordev, &sc->sc_temp[i]);
328 	}
329 	if (lom_init_desc(sc)) {
330 		printf(": can't read sensor names\n");
331 		return;
332 	}
333 
334 	if (sensor_task_register(sc, lom_refresh, 5) == NULL) {
335 		printf(": unable to register update task\n");
336 		return;
337 	}
338 
339 	sensordev_install(&sc->sc_sensordev);
340 
341 	/*
342 	 * We configure the watchdog to turn on the fault LED when the
343 	 * watchdog timer expires.  We run our own timeout to pat it
344 	 * such that this won't happen unless the kernel hangs.  When
345 	 * the watchdog is explicitly configured using sysctl(8), we
346 	 * reconfigure it to reset the machine and let the standard
347 	 * watchdog(4) machinery take over.
348 	 */
349 	lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
350 	lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl);
351 	sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
352 	sc->sc_wdog_ctl |= LOM_WDOG_ENABLE;
353 	lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
354 	timeout_set(&sc->sc_wdog_to, lom_wdog_pat, sc);
355 	timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
356 
357 	wdog_register(lom_wdog_cb, sc);
358 
359 	printf(": %s rev %d.%d\n",
360 	    sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2",
361 	    fw_rev >> 4, fw_rev & 0x0f);
362 }
363 
364 int
lom_activate(struct device * self,int act)365 lom_activate(struct device *self, int act)
366 {
367 	int ret = 0;
368 
369 	switch (act) {
370 	case DVACT_POWERDOWN:
371 		wdog_shutdown(self);
372 		lom_shutdown(self);
373 		break;
374 	}
375 
376 	return (ret);
377 }
378 
379 int
lom_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)380 lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
381 {
382 	if (sc->sc_type < LOM_LOMLITE2)
383 		return lom1_read(sc, reg, val);
384 	else
385 		return lom2_read(sc, reg, val);
386 }
387 
388 int
lom_write(struct lom_softc * sc,uint8_t reg,uint8_t val)389 lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
390 {
391 	if (sc->sc_type < LOM_LOMLITE2)
392 		return lom1_write(sc, reg, val);
393 	else
394 		return lom2_write(sc, reg, val);
395 }
396 
397 void
lom_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)398 lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
399 {
400 	if (sc->sc_type < LOM_LOMLITE2)
401 		return lom1_queue_cmd(sc, lc);
402 	else
403 		return lom2_queue_cmd(sc, lc);
404 }
405 
406 void
lom_dequeue_cmd(struct lom_softc * sc,struct lom_cmd * lc)407 lom_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
408 {
409 	struct lom_cmd *lcp;
410 
411 	mtx_enter(&sc->sc_queue_mtx);
412 	TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) {
413 		if (lcp == lc) {
414 			TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
415 			break;
416 		}
417 	}
418 	mtx_leave(&sc->sc_queue_mtx);
419 }
420 
421 int
lom1_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)422 lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
423 {
424 	struct lom_cmd lc;
425 	int error;
426 
427 	if (cold)
428 		return lom1_read_polled(sc, reg, val);
429 
430 	lc.lc_cmd = reg;
431 	lc.lc_data = 0xff;
432 	lom1_queue_cmd(sc, &lc);
433 
434 	error = tsleep_nsec(&lc, PZERO, "lomrd", SEC_TO_NSEC(1));
435 	if (error)
436 		lom_dequeue_cmd(sc, &lc);
437 
438 	*val = lc.lc_data;
439 
440 	return (error);
441 }
442 
443 int
lom1_write(struct lom_softc * sc,uint8_t reg,uint8_t val)444 lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
445 {
446 	struct lom_cmd lc;
447 	int error;
448 
449 	if (cold)
450 		return lom1_write_polled(sc, reg, val);
451 
452 	lc.lc_cmd = reg | LOM_IDX_WRITE;
453 	lc.lc_data = val;
454 	lom1_queue_cmd(sc, &lc);
455 
456 	error = tsleep_nsec(&lc, PZERO, "lomwr", SEC_TO_NSEC(2));
457 	if (error)
458 		lom_dequeue_cmd(sc, &lc);
459 
460 	return (error);
461 }
462 
463 int
lom1_read_polled(struct lom_softc * sc,uint8_t reg,uint8_t * val)464 lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
465 {
466 	uint8_t str;
467 	int i;
468 
469 	/* Wait for input buffer to become available. */
470 	for (i = 30; i > 0; i--) {
471 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
472 		delay(1000);
473 		if ((str & LOM1_STATUS_BUSY) == 0)
474 			break;
475 	}
476 	if (i == 0)
477 		return (ETIMEDOUT);
478 
479 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
480 
481 	/* Wait until the microcontroller fills output buffer. */
482 	for (i = 30; i > 0; i--) {
483 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
484 		delay(1000);
485 		if ((str & LOM1_STATUS_BUSY) == 0)
486 			break;
487 	}
488 	if (i == 0)
489 		return (ETIMEDOUT);
490 
491 	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
492 	return (0);
493 }
494 
495 int
lom1_write_polled(struct lom_softc * sc,uint8_t reg,uint8_t val)496 lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
497 {
498 	uint8_t str;
499 	int i;
500 
501 	/* Wait for input buffer to become available. */
502 	for (i = 30; i > 0; i--) {
503 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
504 		delay(1000);
505 		if ((str & LOM1_STATUS_BUSY) == 0)
506 			break;
507 	}
508 	if (i == 0)
509 		return (ETIMEDOUT);
510 
511 	reg |= LOM_IDX_WRITE;
512 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);
513 
514 	/* Wait until the microcontroller fills output buffer. */
515 	for (i = 30; i > 0; i--) {
516 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
517 		delay(1000);
518 		if ((str & LOM1_STATUS_BUSY) == 0)
519 			break;
520 	}
521 	if (i == 0)
522 		return (ETIMEDOUT);
523 
524 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val);
525 
526 	return (0);
527 }
528 
529 void
lom1_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)530 lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
531 {
532 	mtx_enter(&sc->sc_queue_mtx);
533 	TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
534 	if (sc->sc_state == LOM_STATE_IDLE) {
535 		sc->sc_state = LOM_STATE_CMD;
536 		lom1_process_queue_locked(sc);
537 	}
538 	mtx_leave(&sc->sc_queue_mtx);
539 }
540 
541 void
lom1_process_queue(void * arg)542 lom1_process_queue(void *arg)
543 {
544 	struct lom_softc *sc = arg;
545 
546 	mtx_enter(&sc->sc_queue_mtx);
547 	lom1_process_queue_locked(sc);
548 	mtx_leave(&sc->sc_queue_mtx);
549 }
550 
551 void
lom1_process_queue_locked(struct lom_softc * sc)552 lom1_process_queue_locked(struct lom_softc *sc)
553 {
554 	struct lom_cmd *lc;
555 	uint8_t str;
556 
557 	lc = TAILQ_FIRST(&sc->sc_queue);
558 	if (lc == NULL) {
559 		sc->sc_state = LOM_STATE_IDLE;
560 		return;
561 	}
562 
563 	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
564 	if (str & LOM1_STATUS_BUSY) {
565 		if (sc->sc_retry++ < 30) {
566 			timeout_add_msec(&sc->sc_state_to, 1);
567 			return;
568 		}
569 
570 		/*
571 		 * Looks like the microcontroller got wedged.  Unwedge
572 		 * it by writing this magic value.  Give it some time
573 		 * to recover.
574 		 */
575 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac);
576 		timeout_add_msec(&sc->sc_state_to, 1000);
577 		sc->sc_state = LOM_STATE_CMD;
578 		return;
579 	}
580 
581 	sc->sc_retry = 0;
582 
583 	if (sc->sc_state == LOM_STATE_CMD) {
584 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd);
585 		sc->sc_state = LOM_STATE_DATA;
586 		timeout_add_msec(&sc->sc_state_to, 250);
587 		return;
588 	}
589 
590 	KASSERT(sc->sc_state == LOM_STATE_DATA);
591 	if ((lc->lc_cmd & LOM_IDX_WRITE) == 0)
592 		lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
593 	else
594 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data);
595 
596 	TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
597 
598 	wakeup(lc);
599 
600 	if (!TAILQ_EMPTY(&sc->sc_queue)) {
601 		sc->sc_state = LOM_STATE_CMD;
602 		timeout_add_msec(&sc->sc_state_to, 1);
603 		return;
604 	}
605 
606 	sc->sc_state = LOM_STATE_IDLE;
607 }
608 
609 int
lom2_read(struct lom_softc * sc,uint8_t reg,uint8_t * val)610 lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
611 {
612 	struct lom_cmd lc;
613 	int error;
614 
615 	if (cold)
616 		return lom2_read_polled(sc, reg, val);
617 
618 	lc.lc_cmd = reg;
619 	lc.lc_data = 0xff;
620 	lom2_queue_cmd(sc, &lc);
621 
622 	error = tsleep_nsec(&lc, PZERO, "lom2rd", SEC_TO_NSEC(1));
623 	if (error)
624 		lom_dequeue_cmd(sc, &lc);
625 
626 	*val = lc.lc_data;
627 
628 	return (error);
629 }
630 
631 int
lom2_read_polled(struct lom_softc * sc,uint8_t reg,uint8_t * val)632 lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
633 {
634 	uint8_t str;
635 	int i;
636 
637 	/* Wait for input buffer to become available. */
638 	for (i = 1000; i > 0; i--) {
639 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
640 		delay(10);
641 		if ((str & LOM2_STATUS_IBF) == 0)
642 			break;
643 	}
644 	if (i == 0)
645 		return (ETIMEDOUT);
646 
647 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
648 
649 	/* Wait until the microcontroller fills output buffer. */
650 	for (i = 1000; i > 0; i--) {
651 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
652 		delay(10);
653 		if (str & LOM2_STATUS_OBF)
654 			break;
655 	}
656 	if (i == 0)
657 		return (ETIMEDOUT);
658 
659 	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
660 	return (0);
661 }
662 
663 int
lom2_write(struct lom_softc * sc,uint8_t reg,uint8_t val)664 lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
665 {
666 	struct lom_cmd lc;
667 	int error;
668 
669 	if (cold)
670 		return lom2_write_polled(sc, reg, val);
671 
672 	lc.lc_cmd = reg | LOM_IDX_WRITE;
673 	lc.lc_data = val;
674 	lom2_queue_cmd(sc, &lc);
675 
676 	error = tsleep_nsec(&lc, PZERO, "lom2wr", SEC_TO_NSEC(1));
677 	if (error)
678 		lom_dequeue_cmd(sc, &lc);
679 
680 	return (error);
681 }
682 
683 int
lom2_write_polled(struct lom_softc * sc,uint8_t reg,uint8_t val)684 lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
685 {
686 	uint8_t str;
687 	int i;
688 
689 	/* Wait for input buffer to become available. */
690 	for (i = 1000; i > 0; i--) {
691 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
692 		delay(10);
693 		if ((str & LOM2_STATUS_IBF) == 0)
694 			break;
695 	}
696 	if (i == 0)
697 		return (ETIMEDOUT);
698 
699 	if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
700 		reg |= LOM_IDX_WRITE;
701 
702 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
703 
704 	/* Wait until the microcontroller fills output buffer. */
705 	for (i = 1000; i > 0; i--) {
706 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
707 		delay(10);
708 		if (str & LOM2_STATUS_OBF)
709 			break;
710 	}
711 	if (i == 0)
712 		return (ETIMEDOUT);
713 
714 	bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
715 
716 	/* Wait for input buffer to become available. */
717 	for (i = 1000; i > 0; i--) {
718 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
719 		delay(10);
720 		if ((str & LOM2_STATUS_IBF) == 0)
721 			break;
722 	}
723 	if (i == 0)
724 		return (ETIMEDOUT);
725 
726 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val);
727 
728 	/* Wait until the microcontroller fills output buffer. */
729 	for (i = 1000; i > 0; i--) {
730 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
731 		delay(10);
732 		if (str & LOM2_STATUS_OBF)
733 			break;
734 	}
735 	if (i == 0)
736 		return (ETIMEDOUT);
737 
738 	bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
739 
740 	/* If we switched spaces, remember the one we're in now. */
741 	if (reg == LOM_IDX_CMD)
742 		sc->sc_space = val;
743 
744 	return (0);
745 }
746 
747 void
lom2_queue_cmd(struct lom_softc * sc,struct lom_cmd * lc)748 lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
749 {
750 	uint8_t str;
751 
752 	mtx_enter(&sc->sc_queue_mtx);
753 	TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
754 	if (sc->sc_state == LOM_STATE_IDLE) {
755 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
756 		if ((str & LOM2_STATUS_IBF) == 0) {
757 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
758 			    LOM2_CMD, lc->lc_cmd);
759 			sc->sc_state = LOM_STATE_DATA;
760 		}
761 	}
762 	mtx_leave(&sc->sc_queue_mtx);
763 }
764 
765 int
lom2_intr(void * arg)766 lom2_intr(void *arg)
767 {
768 	struct lom_softc *sc = arg;
769 	struct lom_cmd *lc;
770 	uint8_t str, obr;
771 
772 	mtx_enter(&sc->sc_queue_mtx);
773 
774 	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
775 	obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
776 
777 	lc = TAILQ_FIRST(&sc->sc_queue);
778 	if (lc == NULL) {
779 		mtx_leave(&sc->sc_queue_mtx);
780 		return (0);
781 	}
782 
783 	if (lc->lc_cmd & LOM_IDX_WRITE) {
784 		bus_space_write_1(sc->sc_iot, sc->sc_ioh,
785 		    LOM2_DATA, lc->lc_data);
786 		lc->lc_cmd &= ~LOM_IDX_WRITE;
787 		mtx_leave(&sc->sc_queue_mtx);
788 		return (1);
789 	}
790 
791 	KASSERT(sc->sc_state == LOM_STATE_DATA);
792 	lc->lc_data = obr;
793 
794 	TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
795 
796 	wakeup(lc);
797 
798 	sc->sc_state = LOM_STATE_IDLE;
799 
800 	if (!TAILQ_EMPTY(&sc->sc_queue)) {
801 		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
802 		if ((str & LOM2_STATUS_IBF) == 0) {
803 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
804 			    LOM2_CMD, lc->lc_cmd);
805 			sc->sc_state = LOM_STATE_DATA;
806 		}
807 	}
808 
809 	mtx_leave(&sc->sc_queue_mtx);
810 
811 	return (1);
812 }
813 
814 int
lom_init_desc(struct lom_softc * sc)815 lom_init_desc(struct lom_softc *sc)
816 {
817 	uint8_t val;
818 	int i, j, k;
819 	int error;
820 
821 	/* LOMlite doesn't provide sensor descriptions. */
822 	if (sc->sc_type < LOM_LOMLITE2)
823 		return (0);
824 
825 	/*
826 	 * Read temperature sensor names.
827 	 */
828 	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP);
829 	if (error)
830 		return (error);
831 
832 	i = 0;
833 	j = 0;
834 	k = LOM_IDX4_TEMP_NAME_START;
835 	while (k <= LOM_IDX4_TEMP_NAME_END) {
836 		error = lom_read(sc, k++, &val);
837 		if (error)
838 			goto fail;
839 
840 		if (val == 0xff)
841 			break;
842 
843 		if (j < sizeof (sc->sc_temp[i].desc) - 1)
844 			sc->sc_temp[i].desc[j++] = val;
845 
846 		if (val == '\0') {
847 			i++;
848 			j = 0;
849 			if (i < sc->sc_num_temp)
850 				continue;
851 
852 			break;
853 		}
854 	}
855 
856 	/*
857 	 * Read fan names.
858 	 */
859 	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN);
860 	if (error)
861 		return (error);
862 
863 	i = 0;
864 	j = 0;
865 	k = LOM_IDX5_FAN_NAME_START;
866 	while (k <= LOM_IDX5_FAN_NAME_END) {
867 		error = lom_read(sc, k++, &val);
868 		if (error)
869 			goto fail;
870 
871 		if (val == 0xff)
872 			break;
873 
874 		if (j < sizeof (sc->sc_fan[i].desc) - 1)
875 			sc->sc_fan[i].desc[j++] = val;
876 
877 		if (val == '\0') {
878 			i++;
879 			j = 0;
880 			if (i < sc->sc_num_fan)
881 				continue;
882 
883 			break;
884 		}
885 	}
886 
887 fail:
888 	lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC);
889 	return (error);
890 }
891 
892 void
lom_refresh(void * arg)893 lom_refresh(void *arg)
894 {
895 	struct lom_softc *sc = arg;
896 	uint8_t val;
897 	int i;
898 
899 	for (i = 0; i < sc->sc_num_fan; i++) {
900 		if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) {
901 			sc->sc_fan[i].flags |= SENSOR_FINVALID;
902 			continue;
903 		}
904 
905 		sc->sc_fan[i].value = (60 * sc->sc_fan_cal[i] * val) / 100;
906 		if (val < sc->sc_fan_low[i])
907 			sc->sc_fan[i].status = SENSOR_S_CRIT;
908 		else
909 			sc->sc_fan[i].status = SENSOR_S_OK;
910 		sc->sc_fan[i].flags &= ~SENSOR_FINVALID;
911 	}
912 
913 	for (i = 0; i < sc->sc_num_psu; i++) {
914 		if (lom_read(sc, LOM_IDX_PSU1 + i, &val) ||
915 		    !ISSET(val, LOM_PSU_PRESENT)) {
916 			sc->sc_psu[i].flags |= SENSOR_FINVALID;
917 			continue;
918 		}
919 
920 		if (val & LOM_PSU_STANDBY) {
921 			sc->sc_psu[i].value = 0;
922 			sc->sc_psu[i].status = SENSOR_S_UNSPEC;
923 		} else {
924 			sc->sc_psu[i].value = 1;
925 			if (ISSET(val, LOM_PSU_INPUTA) &&
926 			    ISSET(val, LOM_PSU_INPUTB) &&
927 			    ISSET(val, LOM_PSU_OUTPUT))
928 				sc->sc_psu[i].status = SENSOR_S_OK;
929 			else
930 				sc->sc_psu[i].status = SENSOR_S_CRIT;
931 		}
932 		sc->sc_psu[i].flags &= ~SENSOR_FINVALID;
933 	}
934 
935 	for (i = 0; i < sc->sc_num_temp; i++) {
936 		if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) {
937 			sc->sc_temp[i].flags |= SENSOR_FINVALID;
938 			continue;
939 		}
940 
941 		sc->sc_temp[i].value = val * 1000000 + 273150000;
942 		sc->sc_temp[i].flags &= ~SENSOR_FINVALID;
943 	}
944 
945 	/*
946 	 * If our hostname is set and differs from what's stored in
947 	 * the LOM, write the new hostname back to the LOM.  Note that
948 	 * we include the terminating NUL when writing the hostname
949 	 * back to the LOM, otherwise the LOM will print any trailing
950 	 * garbage.
951 	 */
952 	if (hostnamelen > 0 &&
953 	    strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) {
954 		if (sc->sc_type < LOM_LOMLITE2)
955 			lom1_write_hostname(sc);
956 		else
957 			lom2_write_hostname(sc);
958 		strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname));
959 	}
960 }
961 
962 void
lom1_write_hostname(struct lom_softc * sc)963 lom1_write_hostname(struct lom_softc *sc)
964 {
965 	char name[(LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1) + 1];
966 	char *p;
967 	int i;
968 
969 	/*
970 	 * LOMlite generally doesn't have enough space to store the
971 	 * fully qualified hostname.  If the hostname is too long,
972 	 * strip off the domain name.
973 	 */
974 	strlcpy(name, hostname, sizeof(name));
975 	if (hostnamelen >= sizeof(name)) {
976 		p = strchr(name, '.');
977 		if (p)
978 			*p = '\0';
979 	}
980 
981 	for (i = 0; i < strlen(name) + 1; i++)
982 		if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i]))
983 			break;
984 }
985 
986 void
lom2_write_hostname(struct lom_softc * sc)987 lom2_write_hostname(struct lom_softc *sc)
988 {
989 	int i;
990 
991 	lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1);
992 	for (i = 0; i < hostnamelen + 1; i++)
993 		lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]);
994 }
995 
996 void
lom_wdog_pat(void * arg)997 lom_wdog_pat(void *arg)
998 {
999 	struct lom_softc *sc = arg;
1000 
1001 	/* Pat the dog. */
1002 	sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
1003 	sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
1004 	lom_queue_cmd(sc, &sc->sc_wdog_pat);
1005 
1006 	timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
1007 }
1008 
1009 int
lom_wdog_cb(void * arg,int period)1010 lom_wdog_cb(void *arg, int period)
1011 {
1012 	struct lom_softc *sc = arg;
1013 
1014 	if (period > LOM_WDOG_TIME_MAX)
1015 		period = LOM_WDOG_TIME_MAX;
1016 	else if (period < 0)
1017 		period = 0;
1018 
1019 	if (period == 0) {
1020 		if (sc->sc_wdog_period != 0) {
1021 			/* Stop watchdog from resetting the machine. */
1022 			sc->sc_wdog_ctl &= ~LOM_WDOG_RESET;
1023 			lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1024 
1025 			lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
1026 			timeout_add_sec(&sc->sc_wdog_to, LOM_WDOG_TIME_MAX / 2);
1027 		}
1028 	} else {
1029 		if (sc->sc_wdog_period != period) {
1030 			/* Set new timeout. */
1031 			lom_write(sc, LOM_IDX_WDOG_TIME, period);
1032 		}
1033 		if (sc->sc_wdog_period == 0) {
1034 			/* Make watchdog reset the machine. */
1035 			sc->sc_wdog_ctl |= LOM_WDOG_RESET;
1036 			lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1037 
1038 			timeout_del(&sc->sc_wdog_to);
1039 		} else {
1040 			/* Pat the dog. */
1041 			lom_dequeue_cmd(sc, &sc->sc_wdog_pat);
1042 			sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
1043 			sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
1044 			lom_queue_cmd(sc, &sc->sc_wdog_pat);
1045 		}
1046 	}
1047 	sc->sc_wdog_period = period;
1048 
1049 	return (period);
1050 }
1051 
1052 void
lom_shutdown(void * arg)1053 lom_shutdown(void *arg)
1054 {
1055 	struct lom_softc *sc = arg;
1056 
1057 	sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE;
1058 	lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
1059 }
1060