lom.c revision 1.7 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 != 0x55 ||
288 lom_read(sc, LOM_IDX_PROBEAA, ®) || 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