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