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