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