Fri Oct 2 15:09:16 2009 UTC ()
Port lom(4) driver for LOMlite lights out management hardware monitor
and watchdog timer from OpenBSD.

It supports the LOMlite found on Sun Netra t1 and the LOMlite2 found
on Sun Netra T1/X1 and Sun Fire V100/V120.


(nakayama)
diff -r1.1160 -r1.1161 src/distrib/sets/lists/man/mi
diff -r1.4 -r1.5 src/share/man/man4/man4.sparc64/Makefile
diff -r0 -r1.1 src/share/man/man4/man4.sparc64/lom.4
diff -r1.110 -r1.111 src/sys/arch/sparc64/conf/GENERIC
diff -r1.120 -r1.121 src/sys/arch/sparc64/conf/files.sparc64
diff -r0 -r1.1 src/sys/arch/sparc64/dev/lom.c

cvs diff -r1.1160 -r1.1161 src/distrib/sets/lists/man/mi (expand / switch to unified diff)

--- src/distrib/sets/lists/man/mi 2009/09/30 22:32:04 1.1160
+++ src/distrib/sets/lists/man/mi 2009/10/02 15:09:16 1.1161
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $NetBSD: mi,v 1.1160 2009/09/30 22:32:04 jmcneill Exp $ 1# $NetBSD: mi,v 1.1161 2009/10/02 15:09:16 nakayama Exp $
2# 2#
3# Note: don't delete entries from here - mark them as "obsolete" instead. 3# Note: don't delete entries from here - mark them as "obsolete" instead.
4# 4#
5./etc/mtree/set.man man-sys-root 5./etc/mtree/set.man man-sys-root
6./usr/share/info/am-utils.info man-amd-info info 6./usr/share/info/am-utils.info man-amd-info info
7./usr/share/info/as.info man-computil-info binutils,info 7./usr/share/info/as.info man-computil-info binutils,info
8./usr/share/info/awk.info man-util-info info 8./usr/share/info/awk.info man-util-info info
9./usr/share/info/bfd.info man-computil-info binutils,info 9./usr/share/info/bfd.info man-computil-info binutils,info
10./usr/share/info/binutils.info man-computil-info binutils,info 10./usr/share/info/binutils.info man-computil-info binutils,info
11./usr/share/info/bzip2.info man-obsolete obsolete 11./usr/share/info/bzip2.info man-obsolete obsolete
12./usr/share/info/cpp.info man-util-info gcccmds,info 12./usr/share/info/cpp.info man-util-info gcccmds,info
13./usr/share/info/cvs.info man-cvs-info cvs,info 13./usr/share/info/cvs.info man-cvs-info cvs,info
14./usr/share/info/cvsclient.info man-cvs-info cvs,info 14./usr/share/info/cvsclient.info man-cvs-info cvs,info
@@ -1451,26 +1451,27 @@ @@ -1451,26 +1451,27 @@
1451./usr/share/man/cat4/sparc/nell.0 man-sys-catman .cat 1451./usr/share/man/cat4/sparc/nell.0 man-sys-catman .cat
1452./usr/share/man/cat4/sparc/openprom.0 man-sys-catman .cat 1452./usr/share/man/cat4/sparc/openprom.0 man-sys-catman .cat
1453./usr/share/man/cat4/sparc/pnozz.0 man-sys-catman .cat 1453./usr/share/man/cat4/sparc/pnozz.0 man-sys-catman .cat
1454./usr/share/man/cat4/sparc/tctrl.0 man-sys-catman .cat 1454./usr/share/man/cat4/sparc/tctrl.0 man-sys-catman .cat
1455./usr/share/man/cat4/sparc/tcx.0 man-sys-catman .cat 1455./usr/share/man/cat4/sparc/tcx.0 man-sys-catman .cat
1456./usr/share/man/cat4/sparc/timer.0 man-sys-catman .cat 1456./usr/share/man/cat4/sparc/timer.0 man-sys-catman .cat
1457./usr/share/man/cat4/sparc/tslot.0 man-sys-catman .cat 1457./usr/share/man/cat4/sparc/tslot.0 man-sys-catman .cat
1458./usr/share/man/cat4/sparc/xd.0 man-sys-catman .cat 1458./usr/share/man/cat4/sparc/xd.0 man-sys-catman .cat
1459./usr/share/man/cat4/sparc/xy.0 man-sys-catman .cat 1459./usr/share/man/cat4/sparc/xy.0 man-sys-catman .cat
1460./usr/share/man/cat4/sparc/zx.0 man-sys-catman .cat 1460./usr/share/man/cat4/sparc/zx.0 man-sys-catman .cat
1461./usr/share/man/cat4/sparc64/envctrl.0 man-sys-catman .cat 1461./usr/share/man/cat4/sparc64/envctrl.0 man-sys-catman .cat
1462./usr/share/man/cat4/sparc64/fdc.0 man-sys-catman .cat 1462./usr/share/man/cat4/sparc64/fdc.0 man-sys-catman .cat
1463./usr/share/man/cat4/sparc64/intro.0 man-sys-catman .cat 1463./usr/share/man/cat4/sparc64/intro.0 man-sys-catman .cat
 1464./usr/share/man/cat4/sparc64/lom.0 man-sys-catman .cat
1464./usr/share/man/cat4/sparc64/sab.0 man-sys-catman .cat 1465./usr/share/man/cat4/sparc64/sab.0 man-sys-catman .cat
1465./usr/share/man/cat4/sparc64/sabtty.0 man-sys-catman .cat 1466./usr/share/man/cat4/sparc64/sabtty.0 man-sys-catman .cat
1466./usr/share/man/cat4/spc.0 man-sys-catman .cat 1467./usr/share/man/cat4/spc.0 man-sys-catman .cat
1467./usr/share/man/cat4/spdmem.0 man-sys-catman .cat 1468./usr/share/man/cat4/spdmem.0 man-sys-catman .cat
1468./usr/share/man/cat4/speaker.0 man-sys-catman .cat 1469./usr/share/man/cat4/speaker.0 man-sys-catman .cat
1469./usr/share/man/cat4/spi.0 man-sys-catman .cat 1470./usr/share/man/cat4/spi.0 man-sys-catman .cat
1470./usr/share/man/cat4/spic.0 man-obsolete obsolete 1471./usr/share/man/cat4/spic.0 man-obsolete obsolete
1471./usr/share/man/cat4/spif.0 man-sys-catman .cat 1472./usr/share/man/cat4/spif.0 man-sys-catman .cat
1472./usr/share/man/cat4/spkr.0 man-sys-catman .cat 1473./usr/share/man/cat4/spkr.0 man-sys-catman .cat
1473./usr/share/man/cat4/spp.0 man-obsolete obsolete 1474./usr/share/man/cat4/spp.0 man-obsolete obsolete
1474./usr/share/man/cat4/sqphy.0 man-sys-catman .cat 1475./usr/share/man/cat4/sqphy.0 man-sys-catman .cat
1475./usr/share/man/cat4/ss.0 man-sys-catman .cat 1476./usr/share/man/cat4/ss.0 man-sys-catman .cat
1476./usr/share/man/cat4/st.0 man-sys-catman .cat 1477./usr/share/man/cat4/st.0 man-sys-catman .cat
@@ -4002,26 +4003,27 @@ @@ -4002,26 +4003,27 @@
4002./usr/share/man/html4/sparc/nell.html man-sys-htmlman html 4003./usr/share/man/html4/sparc/nell.html man-sys-htmlman html
4003./usr/share/man/html4/sparc/openprom.html man-sys-htmlman html 4004./usr/share/man/html4/sparc/openprom.html man-sys-htmlman html
4004./usr/share/man/html4/sparc/pnozz.html man-sys-htmlman html 4005./usr/share/man/html4/sparc/pnozz.html man-sys-htmlman html
4005./usr/share/man/html4/sparc/tctrl.html man-sys-htmlman html 4006./usr/share/man/html4/sparc/tctrl.html man-sys-htmlman html
4006./usr/share/man/html4/sparc/tcx.html man-sys-htmlman html 4007./usr/share/man/html4/sparc/tcx.html man-sys-htmlman html
4007./usr/share/man/html4/sparc/timer.html man-sys-htmlman html 4008./usr/share/man/html4/sparc/timer.html man-sys-htmlman html
4008./usr/share/man/html4/sparc/tslot.html man-sys-htmlman html 4009./usr/share/man/html4/sparc/tslot.html man-sys-htmlman html
4009./usr/share/man/html4/sparc/xd.html man-sys-htmlman html 4010./usr/share/man/html4/sparc/xd.html man-sys-htmlman html
4010./usr/share/man/html4/sparc/xy.html man-sys-htmlman html 4011./usr/share/man/html4/sparc/xy.html man-sys-htmlman html
4011./usr/share/man/html4/sparc/zx.html man-sys-htmlman html 4012./usr/share/man/html4/sparc/zx.html man-sys-htmlman html
4012./usr/share/man/html4/sparc64/envctrl.html man-sys-htmlman html 4013./usr/share/man/html4/sparc64/envctrl.html man-sys-htmlman html
4013./usr/share/man/html4/sparc64/fdc.html man-sys-htmlman html 4014./usr/share/man/html4/sparc64/fdc.html man-sys-htmlman html
4014./usr/share/man/html4/sparc64/intro.html man-sys-htmlman html 4015./usr/share/man/html4/sparc64/intro.html man-sys-htmlman html
 4016./usr/share/man/html4/sparc64/lom.html man-sys-htmlman html
4015./usr/share/man/html4/sparc64/sab.html man-sys-htmlman html 4017./usr/share/man/html4/sparc64/sab.html man-sys-htmlman html
4016./usr/share/man/html4/sparc64/sabtty.html man-sys-htmlman html 4018./usr/share/man/html4/sparc64/sabtty.html man-sys-htmlman html
4017./usr/share/man/html4/spc.html man-sys-htmlman html 4019./usr/share/man/html4/spc.html man-sys-htmlman html
4018./usr/share/man/html4/spdmem.html man-sys-htmlman html 4020./usr/share/man/html4/spdmem.html man-sys-htmlman html
4019./usr/share/man/html4/speaker.html man-sys-htmlman html 4021./usr/share/man/html4/speaker.html man-sys-htmlman html
4020./usr/share/man/html4/spi.html man-sys-htmlman html 4022./usr/share/man/html4/spi.html man-sys-htmlman html
4021./usr/share/man/html4/spif.html man-sys-htmlman html 4023./usr/share/man/html4/spif.html man-sys-htmlman html
4022./usr/share/man/html4/spkr.html man-sys-htmlman html 4024./usr/share/man/html4/spkr.html man-sys-htmlman html
4023./usr/share/man/html4/sqphy.html man-sys-htmlman html 4025./usr/share/man/html4/sqphy.html man-sys-htmlman html
4024./usr/share/man/html4/ss.html man-sys-htmlman html 4026./usr/share/man/html4/ss.html man-sys-htmlman html
4025./usr/share/man/html4/st.html man-sys-htmlman html 4027./usr/share/man/html4/st.html man-sys-htmlman html
4026./usr/share/man/html4/stderr.html man-sys-htmlman html 4028./usr/share/man/html4/stderr.html man-sys-htmlman html
4027./usr/share/man/html4/stdin.html man-sys-htmlman html 4029./usr/share/man/html4/stdin.html man-sys-htmlman html
@@ -6469,26 +6471,27 @@ @@ -6469,26 +6471,27 @@
6469./usr/share/man/man4/sparc/nell.4 man-sys-man .man 6471./usr/share/man/man4/sparc/nell.4 man-sys-man .man
6470./usr/share/man/man4/sparc/openprom.4 man-sys-man .man 6472./usr/share/man/man4/sparc/openprom.4 man-sys-man .man
6471./usr/share/man/man4/sparc/pnozz.4 man-sys-man .man 6473./usr/share/man/man4/sparc/pnozz.4 man-sys-man .man
6472./usr/share/man/man4/sparc/tctrl.4 man-sys-man .man 6474./usr/share/man/man4/sparc/tctrl.4 man-sys-man .man
6473./usr/share/man/man4/sparc/tcx.4 man-sys-man .man 6475./usr/share/man/man4/sparc/tcx.4 man-sys-man .man
6474./usr/share/man/man4/sparc/timer.4 man-sys-man .man 6476./usr/share/man/man4/sparc/timer.4 man-sys-man .man
6475./usr/share/man/man4/sparc/tslot.4 man-sys-man .man 6477./usr/share/man/man4/sparc/tslot.4 man-sys-man .man
6476./usr/share/man/man4/sparc/xd.4 man-sys-man .man 6478./usr/share/man/man4/sparc/xd.4 man-sys-man .man
6477./usr/share/man/man4/sparc/xy.4 man-sys-man .man 6479./usr/share/man/man4/sparc/xy.4 man-sys-man .man
6478./usr/share/man/man4/sparc/zx.4 man-sys-man .man 6480./usr/share/man/man4/sparc/zx.4 man-sys-man .man
6479./usr/share/man/man4/sparc64/envctrl.4 man-sys-man .man 6481./usr/share/man/man4/sparc64/envctrl.4 man-sys-man .man
6480./usr/share/man/man4/sparc64/fdc.4 man-sys-man .man 6482./usr/share/man/man4/sparc64/fdc.4 man-sys-man .man
6481./usr/share/man/man4/sparc64/intro.4 man-sys-man .man 6483./usr/share/man/man4/sparc64/intro.4 man-sys-man .man
 6484./usr/share/man/man4/sparc64/lom.4 man-sys-man .man
6482./usr/share/man/man4/sparc64/sab.4 man-sys-man .man 6485./usr/share/man/man4/sparc64/sab.4 man-sys-man .man
6483./usr/share/man/man4/sparc64/sabtty.4 man-sys-man .man 6486./usr/share/man/man4/sparc64/sabtty.4 man-sys-man .man
6484./usr/share/man/man4/spc.4 man-sys-man .man 6487./usr/share/man/man4/spc.4 man-sys-man .man
6485./usr/share/man/man4/spdmem.4 man-sys-man .man 6488./usr/share/man/man4/spdmem.4 man-sys-man .man
6486./usr/share/man/man4/speaker.4 man-sys-man .man 6489./usr/share/man/man4/speaker.4 man-sys-man .man
6487./usr/share/man/man4/spi.4 man-sys-man .man 6490./usr/share/man/man4/spi.4 man-sys-man .man
6488./usr/share/man/man4/spic.4 man-obsolete obsolete 6491./usr/share/man/man4/spic.4 man-obsolete obsolete
6489./usr/share/man/man4/spif.4 man-sys-man .man 6492./usr/share/man/man4/spif.4 man-sys-man .man
6490./usr/share/man/man4/spkr.4 man-sys-man .man 6493./usr/share/man/man4/spkr.4 man-sys-man .man
6491./usr/share/man/man4/spp.4 man-obsolete obsolete 6494./usr/share/man/man4/spp.4 man-obsolete obsolete
6492./usr/share/man/man4/sqphy.4 man-sys-man .man 6495./usr/share/man/man4/sqphy.4 man-sys-man .man
6493./usr/share/man/man4/ss.4 man-sys-man .man 6496./usr/share/man/man4/ss.4 man-sys-man .man
6494./usr/share/man/man4/st.4 man-sys-man .man 6497./usr/share/man/man4/st.4 man-sys-man .man

cvs diff -r1.4 -r1.5 src/share/man/man4/man4.sparc64/Makefile (expand / switch to unified diff)

--- src/share/man/man4/man4.sparc64/Makefile 2007/05/08 19:23:18 1.4
+++ src/share/man/man4/man4.sparc64/Makefile 2009/10/02 15:09:16 1.5
@@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
1# $NetBSD: Makefile,v 1.4 2007/05/08 19:23:18 jnemeth Exp $ 1# $NetBSD: Makefile,v 1.5 2009/10/02 15:09:16 nakayama Exp $
2 2
3MANSUBDIR=/sparc64 3MANSUBDIR=/sparc64
4 4
5MAN= envctrl.4 fdc.4 intro.4 sab.4 5MAN= envctrl.4 fdc.4 intro.4 lom.4 sab.4
6 6
7MLINKS+= sab.4 sabtty.4 7MLINKS+= sab.4 sabtty.4
8 8
9.include <bsd.man.mk> 9.include <bsd.man.mk>

File Added: src/share/man/man4/man4.sparc64/lom.4
.\"     $NetBSD: lom.4,v 1.1 2009/10/02 15:09:16 nakayama Exp $
.\"     $OpenBSD: lom.4,v 1.4 2009/09/23 22:08:07 kettenis Exp $
.\"
.\" Copyright (c) 2009 Mark Kettenis <kettenis@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: October 2 2009 $
.Dt LOM 4 sparc64
.Os
.Sh NAME
.Nm lom
.Nd lights out management
.Sh SYNOPSIS
.Cd "lom* at ebus?"
.Sh DESCRIPTION
The
.Nm
driver provides support for the LOMlite lights out management module
found on Sun Netra t1 systems and the LOMlite2 module found on Sun
Fire V100/V120 and Sun Netra T1/X1 systems.
Temperature readings, PSU status and fan status provided by the LOM
are made available through the
.Xr envstat 8
interface.
The integrated watchdog timer can be configured through the
.Xr wdogctl 8
interface.
The watchdog timer supports timeouts between 1 and 126 seconds.
.Pp
The
.Nm
driver will update the hostname stored in the LOM whenever the
system's hostname is changed.
.Sh SEE ALSO
.Xr hostname 1 ,
.Xr envsys 4 ,
.Xr envstat 8 ,
.Xr wdogctl 8
.Sh HISTORY
The
.Nm
driver first appeared in
.Ox 4.7
and was then ported to
.Nx 5.1 .
.Sh AUTHORS
The
.Nm
driver was written by
.An Mark Kettenis Aq kettenis@openbsd.org .

cvs diff -r1.110 -r1.111 src/sys/arch/sparc64/conf/GENERIC (expand / switch to unified diff)

--- src/sys/arch/sparc64/conf/GENERIC 2009/03/06 20:31:52 1.110
+++ src/sys/arch/sparc64/conf/GENERIC 2009/10/02 15:09:16 1.111
@@ -1,38 +1,38 @@ @@ -1,38 +1,38 @@
1# $NetBSD: GENERIC,v 1.110 2009/03/06 20:31:52 joerg Exp $ 1# $NetBSD: GENERIC,v 1.111 2009/10/02 15:09:16 nakayama Exp $
2# 2#
3# GENERIC machine description file 3# GENERIC machine description file
4# 4#
5# This machine description file is used to generate the default NetBSD 5# This machine description file is used to generate the default NetBSD
6# kernel. The generic kernel does not include all options, subsystems 6# kernel. The generic kernel does not include all options, subsystems
7# and device drivers, but should be useful for most applications. 7# and device drivers, but should be useful for most applications.
8# 8#
9# The machine description file can be customised for your specific 9# The machine description file can be customised for your specific
10# machine to reduce the kernel size and improve its performance. 10# machine to reduce the kernel size and improve its performance.
11# 11#
12# For further information on compiling NetBSD kernels, see the config(8) 12# For further information on compiling NetBSD kernels, see the config(8)
13# man page. 13# man page.
14# 14#
15# For further information on hardware support for this architecture, see 15# For further information on hardware support for this architecture, see
16# the intro(4) man page. For further information about kernel options 16# the intro(4) man page. For further information about kernel options
17# for this architecture, see the options(4) man page. For an explanation 17# for this architecture, see the options(4) man page. For an explanation
18# of each device driver in this file see the section 4 man page for the 18# of each device driver in this file see the section 4 man page for the
19# device. 19# device.
20 20
21include "arch/sparc64/conf/std.sparc64" 21include "arch/sparc64/conf/std.sparc64"
22 22
23options INCLUDE_CONFIG_FILE # embed config file in kernel binary 23options INCLUDE_CONFIG_FILE # embed config file in kernel binary
24 24
25#ident "GENERIC-$Revision: 1.110 $" 25#ident "GENERIC-$Revision: 1.111 $"
26 26
27maxusers 64 27maxusers 64
28 28
29## System kernel configuration. See options(4) for more detail. 29## System kernel configuration. See options(4) for more detail.
30 30
31 31
32# Options for variants of the Sun SPARC architecure. 32# Options for variants of the Sun SPARC architecure.
33# We currently support three architecture types; at least one is required. 33# We currently support three architecture types; at least one is required.
34options SUN4U # sun4u - UltraSPARC 34options SUN4U # sun4u - UltraSPARC
35#options BLINK # blink the system LED 35#options BLINK # blink the system LED
36 36
37#### System options that are the same for all ports 37#### System options that are the same for all ports
38 38
@@ -874,26 +874,27 @@ wskbd0 at kbd0 @@ -874,26 +874,27 @@ wskbd0 at kbd0
874# sun console as possible 874# sun console as possible
875options WSEMUL_SUN # sun terminal emulation 875options WSEMUL_SUN # sun terminal emulation
876options WS_DEFAULT_FG=WSCOL_BLACK 876options WS_DEFAULT_FG=WSCOL_BLACK
877options WS_DEFAULT_BG=WSCOL_LIGHT_WHITE 877options WS_DEFAULT_BG=WSCOL_LIGHT_WHITE
878options WSDISPLAY_COMPAT_USL # VT handling 878options WSDISPLAY_COMPAT_USL # VT handling
879options WSDISPLAY_COMPAT_RAWKBD # can get raw scancodes 879options WSDISPLAY_COMPAT_RAWKBD # can get raw scancodes
880options WSDISPLAY_DEFAULTSCREENS=4 880options WSDISPLAY_DEFAULTSCREENS=4
881options FONT_GALLANT12x22 # PROM font look-alike 881options FONT_GALLANT12x22 # PROM font look-alike
882 882
883#### Other device configuration 883#### Other device configuration
884 884
885psm* at ebus? # Ultrabook IIi microcontroller 885psm* at ebus? # Ultrabook IIi microcontroller
886envctrl* at ebus? # Ultra E450 environmental monitoring 886envctrl* at ebus? # Ultra E450 environmental monitoring
 887lom* at ebus? # LOMlite lights out management
887 888
888# Netra X1 / T1 style environmental monitoring 889# Netra X1 / T1 style environmental monitoring
889alipm* at pci? 890alipm* at pci?
890iic* at alipm? 891iic* at alipm?
891spdmem* at iic? addr 0x54 892spdmem* at iic? addr 0x54
892spdmem* at iic? addr 0x55 893spdmem* at iic? addr 0x55
893spdmem* at iic? addr 0x56 894spdmem* at iic? addr 0x56
894spdmem* at iic? addr 0x57 895spdmem* at iic? addr 0x57
895admtemp* at iic? addr 0x18 896admtemp* at iic? addr 0x18
896 897
897### Other pseudo-devices 898### Other pseudo-devices
898 899
899pseudo-device crypto # /dev/crypto device 900pseudo-device crypto # /dev/crypto device

cvs diff -r1.120 -r1.121 src/sys/arch/sparc64/conf/files.sparc64 (expand / switch to unified diff)

--- src/sys/arch/sparc64/conf/files.sparc64 2008/12/10 05:56:22 1.120
+++ src/sys/arch/sparc64/conf/files.sparc64 2009/10/02 15:09:16 1.121
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $NetBSD: files.sparc64,v 1.120 2008/12/10 05:56:22 mrg Exp $ 1# $NetBSD: files.sparc64,v 1.121 2009/10/02 15:09:16 nakayama Exp $
2 2
3# @(#)files.sparc64 8.1 (Berkeley) 7/19/93 3# @(#)files.sparc64 8.1 (Berkeley) 7/19/93
4# sparc64-specific configuration info 4# sparc64-specific configuration info
5 5
6# maxpartitions must be first item in files.${ARCH} 6# maxpartitions must be first item in files.${ARCH}
7maxpartitions 8 7maxpartitions 8
8 8
9maxusers 2 8 1024 9maxusers 2 8 1024
10 10
11defflag opt_sparc_arch.h SUN4U 11defflag opt_sparc_arch.h SUN4U
12 12
13define mainbus {} 13define mainbus {}
14device mainbus: mainbus 14device mainbus: mainbus
@@ -57,26 +57,30 @@ attach psm at ebus @@ -57,26 +57,30 @@ attach psm at ebus
57file arch/sparc64/dev/psm.c psm 57file arch/sparc64/dev/psm.c psm
58 58
59device timer 59device timer
60attach timer at mainbus, sbus 60attach timer at mainbus, sbus
61 61
62device power 62device power
63attach power at sbus, ebus 63attach power at sbus, ebus
64file arch/sparc64/dev/power.c power 64file arch/sparc64/dev/power.c power
65 65
66device envctrl: sysmon_envsys, pcf8584, i2cbus 66device envctrl: sysmon_envsys, pcf8584, i2cbus
67attach envctrl at ebus 67attach envctrl at ebus
68file arch/sparc64/dev/envctrl.c envctrl 68file arch/sparc64/dev/envctrl.c envctrl
69 69
 70device lom: sysmon_envsys, sysmon_wdog
 71attach lom at ebus
 72file arch/sparc64/dev/lom.c lom
 73
70device cpu 74device cpu
71attach cpu at mainbus 75attach cpu at mainbus
72file arch/sparc64/sparc64/cpu.c 76file arch/sparc64/sparc64/cpu.c
73 77
74device auxio 78device auxio
75attach auxio at ebus with auxio_ebus 79attach auxio at ebus with auxio_ebus
76attach auxio at sbus with auxio_sbus 80attach auxio at sbus with auxio_sbus
77file arch/sparc64/dev/auxio.c auxio 81file arch/sparc64/dev/auxio.c auxio
78 82
79defflag opt_auxio.h BLINK 83defflag opt_auxio.h BLINK
80 84
81attach lpt at ebus with lpt_ebus 85attach lpt at ebus with lpt_ebus
82file arch/sparc64/dev/lpt_ebus.c lpt_ebus 86file arch/sparc64/dev/lpt_ebus.c lpt_ebus

File Added: src/sys/arch/sparc64/dev/lom.c
/*	$NetBSD: lom.c,v 1.1 2009/10/02 15:09:16 nakayama Exp $	*/
/*	$OpenBSD: lom.c,v 1.15 2009/09/27 18:08:42 kettenis Exp $	*/
/*
 * Copyright (c) 2009 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.1 2009/10/02 15:09:16 nakayama Exp $");

#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/envsys.h>
#include <sys/systm.h>
#include <sys/callout.h>

#include <machine/autoconf.h>

#include <dev/ebus/ebusreg.h>
#include <dev/ebus/ebusvar.h>
#include <dev/sysmon/sysmonvar.h>

/*
 * LOMlite is a so far unidentified microcontroller.
 */
#define LOM1_STATUS		0x00	/* R */
#define  LOM1_STATUS_BUSY	0x80
#define LOM1_CMD		0x00	/* W */
#define LOM1_DATA		0x01	/* R/W */

/*
 * LOMlite2 is implemented as a H8/3437 microcontroller which has its
 * on-chip host interface hooked up to EBus.
 */
#define LOM2_DATA		0x00	/* R/W */
#define LOM2_CMD		0x01	/* W */
#define LOM2_STATUS		0x01	/* R */
#define  LOM2_STATUS_OBF	0x01	/* Output Buffer Full */
#define  LOM2_STATUS_IBF	0x02	/* Input Buffer Full  */

#define LOM_IDX_CMD		0x00
#define  LOM_IDX_CMD_GENERIC	0x00
#define  LOM_IDX_CMD_TEMP	0x04
#define  LOM_IDX_CMD_FAN	0x05

#define LOM_IDX_FW_REV		0x01	/* Firmware revision  */

#define LOM_IDX_FAN1		0x04	/* Fan speed */
#define LOM_IDX_FAN2		0x05
#define LOM_IDX_FAN3		0x06
#define LOM_IDX_FAN4		0x07
#define LOM_IDX_PSU1		0x08	/* PSU status */
#define LOM_IDX_PSU2		0x09
#define LOM_IDX_PSU3		0x0a
#define  LOM_PSU_INPUTA		0x01
#define  LOM_PSU_INPUTB		0x02
#define  LOM_PSU_OUTPUT		0x04
#define  LOM_PSU_PRESENT	0x08
#define  LOM_PSU_STANDBY	0x10

#define LOM_IDX_TEMP1		0x18	/* Temperature */
#define LOM_IDX_TEMP2		0x19
#define LOM_IDX_TEMP3		0x1a
#define LOM_IDX_TEMP4		0x1b
#define LOM_IDX_TEMP5		0x1c
#define LOM_IDX_TEMP6		0x1d
#define LOM_IDX_TEMP7		0x1e
#define LOM_IDX_TEMP8		0x1f

#define LOM_IDX_LED1		0x25

#define LOM_IDX_ALARM		0x30
#define LOM_IDX_WDOG_CTL	0x31
#define  LOM_WDOG_ENABLE	0x01
#define  LOM_WDOG_RESET		0x02
#define  LOM_WDOG_AL3_WDOG	0x04
#define  LOM_WDOG_AL3_FANPSU	0x08
#define LOM_IDX_WDOG_TIME	0x32
#define  LOM_WDOG_TIME_MAX	126

#define LOM1_IDX_HOSTNAME1	0x33
#define LOM1_IDX_HOSTNAME2	0x34
#define LOM1_IDX_HOSTNAME3	0x35
#define LOM1_IDX_HOSTNAME4	0x36
#define LOM1_IDX_HOSTNAME5	0x37
#define LOM1_IDX_HOSTNAME6	0x38
#define LOM1_IDX_HOSTNAME7	0x39
#define LOM1_IDX_HOSTNAME8	0x3a
#define LOM1_IDX_HOSTNAME9	0x3b
#define LOM1_IDX_HOSTNAME10	0x3c
#define LOM1_IDX_HOSTNAME11	0x3d
#define LOM1_IDX_HOSTNAME12	0x3e

#define LOM2_IDX_HOSTNAMELEN	0x38
#define LOM2_IDX_HOSTNAME	0x39

#define LOM_IDX_CONFIG		0x5d
#define LOM_IDX_FAN1_CAL	0x5e
#define LOM_IDX_FAN2_CAL	0x5f
#define LOM_IDX_FAN3_CAL	0x60
#define LOM_IDX_FAN4_CAL	0x61
#define LOM_IDX_FAN1_LOW	0x62
#define LOM_IDX_FAN2_LOW	0x63
#define LOM_IDX_FAN3_LOW	0x64
#define LOM_IDX_FAN4_LOW	0x65

#define LOM_IDX_CONFIG2		0x66
#define LOM_IDX_CONFIG3		0x67

#define LOM_IDX_PROBE55		0x7e	/* Always returns 0x55 */
#define LOM_IDX_PROBEAA		0x7f	/* Always returns 0xaa */

#define LOM_IDX_WRITE		0x80

#define LOM_IDX4_TEMP_NAME_START	0x40
#define LOM_IDX4_TEMP_NAME_END		0xff

#define LOM_IDX5_FAN_NAME_START		0x40
#define LOM_IDX5_FAN_NAME_END		0xff

#define LOM_MAX_FAN	4
#define LOM_MAX_PSU	3
#define LOM_MAX_TEMP	8

struct lom_cmd {
	uint8_t			lc_cmd;
	uint8_t			lc_data;

	TAILQ_ENTRY(lom_cmd)	lc_next;
};

struct lom_softc {
	device_t		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	int			sc_type;
#define LOM_LOMLITE		0
#define LOM_LOMLITE2		2
	int			sc_space;

	struct sysmon_envsys	*sc_sme;
	envsys_data_t		sc_fan[LOM_MAX_FAN];
	envsys_data_t		sc_psu[LOM_MAX_PSU];
	envsys_data_t		sc_temp[LOM_MAX_TEMP];

	int			sc_num_fan;
	int			sc_num_psu;
	int			sc_num_temp;

	uint8_t			sc_fan_cal[LOM_MAX_FAN];
	uint8_t			sc_fan_low[LOM_MAX_FAN];

	char			sc_hostname[MAXHOSTNAMELEN];

	struct sysmon_wdog	sc_smw;
	int			sc_wdog_period;
	uint8_t			sc_wdog_ctl;
	struct lom_cmd		sc_wdog_pat;

	TAILQ_HEAD(, lom_cmd)	sc_queue;
	kmutex_t		sc_queue_mtx;
	struct callout		sc_state_to;
	int			sc_state;
#define LOM_STATE_IDLE		0
#define LOM_STATE_CMD		1
#define LOM_STATE_DATA		2
	int			sc_retry;
};

static int	lom_match(device_t, cfdata_t, void *);
static void	lom_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(lom, sizeof(struct lom_softc),
    lom_match, lom_attach, NULL, NULL);

static int	lom_read(struct lom_softc *, uint8_t, uint8_t *);
static int	lom_write(struct lom_softc *, uint8_t, uint8_t);
static void	lom_queue_cmd(struct lom_softc *, struct lom_cmd *);
static int	lom1_read(struct lom_softc *, uint8_t, uint8_t *);
static int	lom1_write(struct lom_softc *, uint8_t, uint8_t);
static int	lom1_read_polled(struct lom_softc *, uint8_t, uint8_t *);
static int	lom1_write_polled(struct lom_softc *, uint8_t, uint8_t);
static void	lom1_queue_cmd(struct lom_softc *, struct lom_cmd *);
static void	lom1_dequeue_cmd(struct lom_softc *, struct lom_cmd *);
static void	lom1_process_queue(void *);
static void	lom1_process_queue_locked(struct lom_softc *);
static int	lom2_read(struct lom_softc *, uint8_t, uint8_t *);
static int	lom2_write(struct lom_softc *, uint8_t, uint8_t);
static void	lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);

static int	lom_init_desc(struct lom_softc *);
static void	lom_refresh(struct sysmon_envsys *, envsys_data_t *);
static void	lom1_write_hostname(struct lom_softc *);
static void	lom2_write_hostname(struct lom_softc *);

static int	lom_wdog_tickle(struct sysmon_wdog *);
static int	lom_wdog_setmode(struct sysmon_wdog *);

static int
lom_match(device_t parent, cfdata_t match, void *aux)
{
	struct ebus_attach_args *ea = aux;

	if (strcmp(ea->ea_name, "SUNW,lom") == 0 ||
	    strcmp(ea->ea_name, "SUNW,lomh") == 0)
		return (1);

	return (0);
}

static void
lom_attach(device_t parent, device_t self, void *aux)
{
	struct lom_softc *sc = device_private(self);
	struct ebus_attach_args *ea = aux;
	uint8_t reg, fw_rev, config, config2, config3;
	uint8_t cal, low;
	int i;

	if (strcmp(ea->ea_name, "SUNW,lomh") == 0)
		sc->sc_type = LOM_LOMLITE2;

	sc->sc_dev = self;
	sc->sc_iot = ea->ea_bustag;
	if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
	    ea->ea_reg[0].size, 0, &sc->sc_ioh) != 0) {
		aprint_error(": can't map register space\n");
		return;
	}

	if (sc->sc_type < LOM_LOMLITE2) {
		/* XXX Magic */
		(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
		bus_space_write_1(sc->sc_iot, sc->sc_ioh, 3, 0xca);

		TAILQ_INIT(&sc->sc_queue);
		mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_VM);
		callout_init(&sc->sc_state_to, 0);
		callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc);
	}

	if (lom_read(sc, LOM_IDX_PROBE55, &reg) || reg != 0x55 ||
	    lom_read(sc, LOM_IDX_PROBEAA, &reg) || reg != 0xaa ||
	    lom_read(sc, LOM_IDX_FW_REV, &fw_rev) ||
	    lom_read(sc, LOM_IDX_CONFIG, &config))
	{
		aprint_error(": not responding\n");
		return;
	}

	aprint_normal(": %s: %s rev %d.%d\n", ea->ea_name,
	    sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2",
	    fw_rev >> 4, fw_rev & 0x0f);

	config2 = config3 = 0;
	if (sc->sc_type >= LOM_LOMLITE2) {
		lom_read(sc, LOM_IDX_CONFIG2, &config2);
		lom_read(sc, LOM_IDX_CONFIG3, &config3);
	}

	sc->sc_num_fan = min((config >> 5) & 0x7, LOM_MAX_FAN);
	sc->sc_num_psu = min((config >> 3) & 0x3, LOM_MAX_PSU);
	sc->sc_num_temp = min((config2 >> 4) & 0xf, LOM_MAX_TEMP);

	aprint_verbose_dev(self, "%d fan(s), %d PSU(s), %d temp sensor(s)\n",
	    sc->sc_num_fan, sc->sc_num_psu, sc->sc_num_temp);

	for (i = 0; i < sc->sc_num_fan; i++) {
		if (lom_read(sc, LOM_IDX_FAN1_CAL + i, &cal) ||
		    lom_read(sc, LOM_IDX_FAN1_LOW + i, &low)) {
			aprint_error_dev(self, "can't read fan information\n");
			return;
		}
		sc->sc_fan_cal[i] = cal;
		sc->sc_fan_low[i] = low;
	}

	/* Initialize sensor data. */
	sc->sc_sme = sysmon_envsys_create();
	for (i = 0; i < sc->sc_num_fan; i++) {
		sc->sc_fan[i].units = ENVSYS_SFANRPM;
		snprintf(sc->sc_fan[i].desc, sizeof(sc->sc_fan[i].desc),
		    "fan%d", i + 1);
		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan[i])) {
			sysmon_envsys_destroy(sc->sc_sme);
			aprint_error_dev(self, "can't attach fan sensor\n");
			return;
		}
	}
	for (i = 0; i < sc->sc_num_psu; i++) {
		sc->sc_psu[i].units = ENVSYS_INDICATOR;
		snprintf(sc->sc_psu[i].desc, sizeof(sc->sc_psu[i].desc),
		    "PSU%d", i + 1);
		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_psu[i])) {
			sysmon_envsys_destroy(sc->sc_sme);
			aprint_error_dev(self, "can't attach PSU sensor\n");
			return;
		}
	}
	for (i = 0; i < sc->sc_num_temp; i++) {
		sc->sc_temp[i].units = ENVSYS_STEMP;
		snprintf(sc->sc_temp[i].desc, sizeof(sc->sc_temp[i].desc),
		    "temp%d", i + 1);
		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp[i])) {
			sysmon_envsys_destroy(sc->sc_sme);
			aprint_error_dev(self, "can't attach temp sensor\n");
			return;
		}
	}
	if (lom_init_desc(sc)) {
		aprint_error_dev(self, "can't read sensor names\n");
		sysmon_envsys_destroy(sc->sc_sme);
		return;
	}

	sc->sc_sme->sme_name = device_xname(self);
	sc->sc_sme->sme_cookie = sc;
	sc->sc_sme->sme_refresh = lom_refresh;
	if (sysmon_envsys_register(sc->sc_sme)) {
		aprint_error_dev(self,
		    "unable to register envsys with sysmon\n");
		sysmon_envsys_destroy(sc->sc_sme);
		return;
	}

	/* Initialize watchdog. */
	lom_write(sc, LOM_IDX_WDOG_TIME, LOM_WDOG_TIME_MAX);
	lom_read(sc, LOM_IDX_WDOG_CTL, &sc->sc_wdog_ctl);
	sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET);
	lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);

	sc->sc_wdog_period = LOM_WDOG_TIME_MAX;

	sc->sc_smw.smw_name = device_xname(self);
	sc->sc_smw.smw_cookie = sc;
	sc->sc_smw.smw_setmode = lom_wdog_setmode;
	sc->sc_smw.smw_tickle = lom_wdog_tickle;
	sc->sc_smw.smw_period = sc->sc_wdog_period;
	if (sysmon_wdog_register(&sc->sc_smw)) {
		aprint_error_dev(self,
		    "unable to register wdog with sysmon\n");
		return;
	}

	aprint_verbose_dev(self, "Watchdog timer configured.\n");
}

static int
lom_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
{
	if (sc->sc_type < LOM_LOMLITE2)
		return lom1_read(sc, reg, val);
	else
		return lom2_read(sc, reg, val);
}

static int
lom_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
{
	if (sc->sc_type < LOM_LOMLITE2)
		return lom1_write(sc, reg, val);
	else
		return lom2_write(sc, reg, val);
}

static void
lom_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
{
	if (sc->sc_type < LOM_LOMLITE2)
		return lom1_queue_cmd(sc, lc);
	else
		return lom2_queue_cmd(sc, lc);
}

static int
lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
{
	struct lom_cmd lc;
	int error;

	if (cold)
		return lom1_read_polled(sc, reg, val);

	lc.lc_cmd = reg;
	lc.lc_data = 0xff;
	lom1_queue_cmd(sc, &lc);

	error = tsleep(&lc, PZERO, "lomrd", hz);
	if (error)
		lom1_dequeue_cmd(sc, &lc);

	*val = lc.lc_data;

	return (error);
}

static int
lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
{
	struct lom_cmd lc;
	int error;

	if (cold)
		return lom1_write_polled(sc, reg, val);

	lc.lc_cmd = reg | LOM_IDX_WRITE;
	lc.lc_data = val;
	lom1_queue_cmd(sc, &lc);

	error = tsleep(&lc, PZERO, "lomwr", hz);
	if (error)
		lom1_dequeue_cmd(sc, &lc);

	return (error);
}

static int
lom1_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
{
	uint8_t str;
	int i;

	/* Wait for input buffer to become available. */
	for (i = 30; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
		delay(1000);
		if ((str & LOM1_STATUS_BUSY) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);

	/* Wait until the microcontroller fills output buffer. */
	for (i = 30; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
		delay(1000);
		if ((str & LOM1_STATUS_BUSY) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
	return (0);
}

static int
lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
{
	uint8_t str;
	int i;

	/* Wait for input buffer to become available. */
	for (i = 30; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
		delay(1000);
		if ((str & LOM1_STATUS_BUSY) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	reg |= LOM_IDX_WRITE;
	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, reg);

	/* Wait until the microcontroller fills output buffer. */
	for (i = 30; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
		delay(1000);
		if ((str & LOM1_STATUS_BUSY) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, val);

	return (0);
}

static void
lom1_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
{
	mutex_enter(&sc->sc_queue_mtx);
	TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
	if (sc->sc_state == LOM_STATE_IDLE) {
		sc->sc_state = LOM_STATE_CMD;
		lom1_process_queue_locked(sc);
	}
	mutex_exit(&sc->sc_queue_mtx);
}

static void
lom1_dequeue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
{
	struct lom_cmd *lcp;

	mutex_enter(&sc->sc_queue_mtx);
	TAILQ_FOREACH(lcp, &sc->sc_queue, lc_next) {
		if (lcp == lc) {
			TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
			break;
		}
	}
	mutex_exit(&sc->sc_queue_mtx);
}

static void
lom1_process_queue(void *arg)
{
	struct lom_softc *sc = arg;

	mutex_enter(&sc->sc_queue_mtx);
	lom1_process_queue_locked(sc);
	mutex_exit(&sc->sc_queue_mtx);
}

static void
lom1_process_queue_locked(struct lom_softc *sc)
{
	struct lom_cmd *lc;
	uint8_t str;

	lc = TAILQ_FIRST(&sc->sc_queue);
	KASSERT(lc != NULL);

	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
	if (str & LOM1_STATUS_BUSY) {
		if (sc->sc_retry++ > 30)
			return;
		callout_schedule(&sc->sc_state_to, mstohz(1));
		return;
	}

	sc->sc_retry = 0;

	if (sc->sc_state == LOM_STATE_CMD) {
		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_CMD, lc->lc_cmd);
		sc->sc_state = LOM_STATE_DATA;
		callout_schedule(&sc->sc_state_to, mstohz(250));
		return;
	}

	KASSERT(sc->sc_state == LOM_STATE_DATA);
	if ((lc->lc_cmd & LOM_IDX_WRITE) == 0)
		lc->lc_data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA);
	else
		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, lc->lc_data);

	TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);

	wakeup(lc);

	if (!TAILQ_EMPTY(&sc->sc_queue)) {
		sc->sc_state = LOM_STATE_CMD;
		callout_schedule(&sc->sc_state_to, mstohz(1));
		return;
	}

	sc->sc_state = LOM_STATE_IDLE;
}

static int
lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
{
	uint8_t str;
	int i;

	/* Wait for input buffer to become available. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if ((str & LOM2_STATUS_IBF) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);

	/* Wait until the microcontroller fills output buffer. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if (str & LOM2_STATUS_OBF)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	*val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
	return (0);
}

static int
lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
{
	uint8_t str;
	int i;

	/* Wait for input buffer to become available. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if ((str & LOM2_STATUS_IBF) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
		reg |= 0x80;

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);

	/* Wait until the microcontroller fills output buffer. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if (str & LOM2_STATUS_OBF)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);

	/* Wait for input buffer to become available. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if ((str & LOM2_STATUS_IBF) == 0)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA, val);

	/* Wait until the microcontroller fills output buffer. */
	for (i = 1000; i > 0; i--) {
		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
		delay(10);
		if (str & LOM2_STATUS_OBF)
			break;
	}
	if (i == 0)
		return (ETIMEDOUT);

	(void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);

	/* If we switched spaces, remember the one we're in now. */
	if (reg == LOM_IDX_CMD)
		sc->sc_space = val;

	return (0);
}

static void
lom2_queue_cmd(struct lom_softc *sc, struct lom_cmd *lc)
{
	KASSERT(lc->lc_cmd & LOM_IDX_WRITE);
	lom2_write(sc, lc->lc_cmd, lc->lc_data);
}

static int
lom_init_desc(struct lom_softc *sc)
{
	uint8_t val;
	int i, j, k;
	int error;

	/* LOMlite doesn't provide sensor descriptions. */
	if (sc->sc_type < LOM_LOMLITE2)
		return (0);

	/*
	 * Read temperature sensor names.
	 */
	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_TEMP);
	if (error)
		return (error);

	i = 0;
	j = 0;
	k = LOM_IDX4_TEMP_NAME_START;
	while (k <= LOM_IDX4_TEMP_NAME_END) {
		error = lom_read(sc, k++, &val);
		if (error)
			goto fail;

		if (val == 0xff)
			break;

		if (j < sizeof (sc->sc_temp[i].desc) - 1)
			sc->sc_temp[i].desc[j++] = val;

		if (val == '\0') {
			i++;
			j = 0;
			if (i < sc->sc_num_temp)
				continue;

			break;
		}
	}

	/*
	 * Read fan names.
	 */
	error = lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_FAN);
	if (error)
		return (error);

	i = 0;
	j = 0;
	k = LOM_IDX5_FAN_NAME_START;
	while (k <= LOM_IDX5_FAN_NAME_END) {
		error = lom_read(sc, k++, &val);
		if (error)
			goto fail;

		if (val == 0xff)
			break;

		if (j < sizeof (sc->sc_fan[i].desc) - 1)
			sc->sc_fan[i].desc[j++] = val;

		if (val == '\0') {
			i++;
			j = 0;
			if (i < sc->sc_num_fan)
				continue;

			break;
		}
	}

fail:
	lom_write(sc, LOM_IDX_CMD, LOM_IDX_CMD_GENERIC);
	return (error);
}

static void
lom_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
	struct lom_softc *sc = sme->sme_cookie;
	uint8_t val;
	int i;

	for (i = 0; i < sc->sc_num_fan; i++) {
		if (lom_read(sc, LOM_IDX_FAN1 + i, &val)) {
			sc->sc_fan[i].state = ENVSYS_SINVALID;
			continue;
		}

		sc->sc_fan[i].value_cur = (60 * sc->sc_fan_cal[i] * val) / 100;
		if (val < sc->sc_fan_low[i])
			sc->sc_fan[i].state = ENVSYS_SCRITICAL;
		else
			sc->sc_fan[i].state = ENVSYS_SVALID;
	}

	for (i = 0; i < sc->sc_num_psu; i++) {
		if (lom_read(sc, LOM_IDX_PSU1 + i, &val) ||
		    !ISSET(val, LOM_PSU_PRESENT)) {
			sc->sc_psu[i].state = ENVSYS_SINVALID;
			continue;
		}

		if (val & LOM_PSU_STANDBY) {
			sc->sc_psu[i].value_cur = 0;
			sc->sc_psu[i].state = ENVSYS_SVALID;
		} else {
			sc->sc_psu[i].value_cur = 1;
			if (ISSET(val, LOM_PSU_INPUTA) &&
			    ISSET(val, LOM_PSU_INPUTB) &&
			    ISSET(val, LOM_PSU_OUTPUT))
				sc->sc_psu[i].state = ENVSYS_SVALID;
			else
				sc->sc_psu[i].state = ENVSYS_SCRITICAL;
		}
	}

	for (i = 0; i < sc->sc_num_temp; i++) {
		if (lom_read(sc, LOM_IDX_TEMP1 + i, &val)) {
			sc->sc_temp[i].state = ENVSYS_SINVALID;
			continue;
		}

		sc->sc_temp[i].value_cur = val * 1000000 + 273150000;
		sc->sc_temp[i].state = ENVSYS_SVALID;
	}

	/*
	 * If our hostname is set and differs from what's stored in
	 * the LOM, write the new hostname back to the LOM.  Note that
	 * we include the terminating NUL when writing the hostname
	 * back to the LOM, otherwise the LOM will print any trailing
	 * garbage.
	 */
	if (hostnamelen > 0 &&
	    strncmp(sc->sc_hostname, hostname, sizeof(hostname)) != 0) {
		if (sc->sc_type < LOM_LOMLITE2)
			lom1_write_hostname(sc);
		else
			lom2_write_hostname(sc);
		strlcpy(sc->sc_hostname, hostname, sizeof(hostname));
	}
}

static void
lom1_write_hostname(struct lom_softc *sc)
{
	char name[LOM1_IDX_HOSTNAME12 - LOM1_IDX_HOSTNAME1 + 1];
	char *p;
	int i;

	/*
	 * LOMlite generally doesn't have enough space to store the
	 * fully qualified hostname.  If the hostname is too long,
	 * strip off the domain name.
	 */
	strlcpy(name, hostname, sizeof(name));
	if (hostnamelen > sizeof(name)) {
		p = strchr(name, '.');
		if (p)
			*p = '\0';
	}

	for (i = 0; i < strlen(name) + 1; i++)
		if (lom_write(sc, LOM1_IDX_HOSTNAME1 + i, name[i]))
			break;
}

static void
lom2_write_hostname(struct lom_softc *sc)
{
	int i;

	lom_write(sc, LOM2_IDX_HOSTNAMELEN, hostnamelen + 1);
	for (i = 0; i < hostnamelen + 1; i++)
		lom_write(sc, LOM2_IDX_HOSTNAME, hostname[i]);
}

static int
lom_wdog_tickle(struct sysmon_wdog *smw)
{
	struct lom_softc *sc = smw->smw_cookie;

	/* Pat the dog. */
	sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
	sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
	lom_queue_cmd(sc, &sc->sc_wdog_pat);

	return 0;
}

static int
lom_wdog_setmode(struct sysmon_wdog *smw)
{
	struct lom_softc *sc = smw->smw_cookie;

	if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
		/* disable watchdog */
		sc->sc_wdog_ctl &= ~(LOM_WDOG_ENABLE|LOM_WDOG_RESET);
		lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
	} else {
		if (smw->smw_period == WDOG_PERIOD_DEFAULT)
			smw->smw_period = sc->sc_wdog_period;
		else if (smw->smw_period == 0 ||
		    smw->smw_period > LOM_WDOG_TIME_MAX)
			return EINVAL;
		lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period);

		/* enable watchdog */
		sc->sc_wdog_ctl |= LOM_WDOG_ENABLE|LOM_WDOG_RESET;
		sc->sc_wdog_pat.lc_cmd = LOM_IDX_WDOG_CTL | LOM_IDX_WRITE;
		sc->sc_wdog_pat.lc_data = sc->sc_wdog_ctl;
		lom_queue_cmd(sc, &sc->sc_wdog_pat);
	}

	return 0;
}