Module Name:    src
Committed By:   bouyer
Date:           Sat Nov 28 15:55:14 UTC 2009

Modified Files:
        src/share/man/man4/man4.sparc64 [netbsd-5]: lom.4
        src/sys/arch/sparc64/dev [netbsd-5]: lom.c

Log Message:
Pull up following revision(s) (requested by nakayama in ticket #1151):
        share/man/man4/man4.sparc64/lom.4: revision 1.3
        sys/arch/sparc64/dev/lom.c: revision 1.2, 1.3
Merge changes between revision 1.16 and 1.19 of OpenBSD with
shutdownhook_establish(9) to pmf(9) conversion:
- LOMlite seems to get wedged from time to time; add some code to unwedge it.
- Make sure we don't insert and entry into the list of pending commends twice.
- Establish a shutdown hook to disable the watchdog timer to prevent watchdog
  triggers after the kernel has been halted.
- Handle LOMlite2 in an interrupt-driven way; avoids using delay(9) once the
  machine is up and running.
Add support for monitoring Fault LED and Alarms status.


To generate a diff of this commit:
cvs rdiff -u -r1.2.2.2 -r1.2.2.3 src/share/man/man4/man4.sparc64/lom.4
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/arch/sparc64/dev/lom.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/man4.sparc64/lom.4
diff -u src/share/man/man4/man4.sparc64/lom.4:1.2.2.2 src/share/man/man4/man4.sparc64/lom.4:1.2.2.3
--- src/share/man/man4/man4.sparc64/lom.4:1.2.2.2	Fri Oct 16 11:56:10 2009
+++ src/share/man/man4/man4.sparc64/lom.4	Sat Nov 28 15:55:14 2009
@@ -1,4 +1,4 @@
-.\"     $NetBSD: lom.4,v 1.2.2.2 2009/10/16 11:56:10 sborrill Exp $
+.\"     $NetBSD: lom.4,v 1.2.2.3 2009/11/28 15:55:14 bouyer Exp $
 .\"     $OpenBSD: lom.4,v 1.4 2009/09/23 22:08:07 kettenis Exp $
 .\"
 .\" Copyright (c) 2009 Mark Kettenis <kette...@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd October 2, 2009
+.Dd November 28, 2009
 .Dt LOM 4 sparc64
 .Os
 .Sh NAME
@@ -29,8 +29,8 @@
 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
+Fault LED and alarms status, 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

Index: src/sys/arch/sparc64/dev/lom.c
diff -u src/sys/arch/sparc64/dev/lom.c:1.1.2.2 src/sys/arch/sparc64/dev/lom.c:1.1.2.3
--- src/sys/arch/sparc64/dev/lom.c:1.1.2.2	Fri Oct 16 11:56:11 2009
+++ src/sys/arch/sparc64/dev/lom.c	Sat Nov 28 15:55:14 2009
@@ -1,5 +1,5 @@
-/*	$NetBSD: lom.c,v 1.1.2.2 2009/10/16 11:56:11 sborrill Exp $	*/
-/*	$OpenBSD: lom.c,v 1.15 2009/09/27 18:08:42 kettenis Exp $	*/
+/*	$NetBSD: lom.c,v 1.1.2.3 2009/11/28 15:55:14 bouyer Exp $	*/
+/*	$OpenBSD: lom.c,v 1.19 2009/11/10 22:26:48 kettenis Exp $	*/
 /*
  * Copyright (c) 2009 Mark Kettenis
  *
@@ -17,7 +17,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.1.2.2 2009/10/16 11:56:11 sborrill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lom.c,v 1.1.2.3 2009/11/28 15:55:14 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -83,6 +83,10 @@
 #define LOM_IDX_LED1		0x25
 
 #define LOM_IDX_ALARM		0x30
+#define  LOM_ALARM_1		0x01
+#define  LOM_ALARM_2		0x02
+#define  LOM_ALARM_3		0x04
+#define  LOM_ALARM_FAULT	0xf0
 #define LOM_IDX_WDOG_CTL	0x31
 #define  LOM_WDOG_ENABLE	0x01
 #define  LOM_WDOG_RESET		0x02
@@ -131,6 +135,7 @@
 #define LOM_IDX5_FAN_NAME_START		0x40
 #define LOM_IDX5_FAN_NAME_END		0xff
 
+#define LOM_MAX_ALARM	4
 #define LOM_MAX_FAN	4
 #define LOM_MAX_PSU	3
 #define LOM_MAX_TEMP	8
@@ -153,10 +158,12 @@
 	int			sc_space;
 
 	struct sysmon_envsys	*sc_sme;
+	envsys_data_t		sc_alarm[LOM_MAX_ALARM];
 	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_alarm;
 	int			sc_num_fan;
 	int			sc_num_psu;
 	int			sc_num_temp;
@@ -190,17 +197,20 @@
 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 void	lom_dequeue_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 int	lom2_read_polled(struct lom_softc *, uint8_t, uint8_t *);
+static int	lom2_write_polled(struct lom_softc *, uint8_t, uint8_t);
 static void	lom2_queue_cmd(struct lom_softc *, struct lom_cmd *);
+static int	lom2_intr(void *);
 
 static int	lom_init_desc(struct lom_softc *);
 static void	lom_refresh(struct sysmon_envsys *, envsys_data_t *);
@@ -210,6 +220,8 @@
 static int	lom_wdog_tickle(struct sysmon_wdog *);
 static int	lom_wdog_setmode(struct sysmon_wdog *);
 
+static bool	lom_shutdown(device_t, int);
+
 static int
 lom_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -231,8 +243,13 @@
 	uint8_t cal, low;
 	int i;
 
-	if (strcmp(ea->ea_name, "SUNW,lomh") == 0)
+	if (strcmp(ea->ea_name, "SUNW,lomh") == 0) {
+		if (ea->ea_nintr < 1) {
+			aprint_error(": no interrupt\n");
+			return;
+		}
 		sc->sc_type = LOM_LOMLITE2;
+	}
 
 	sc->sc_dev = self;
 	sc->sc_iot = ea->ea_bustag;
@@ -246,11 +263,6 @@
 		/* 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 ||
@@ -266,12 +278,26 @@
 	    sc->sc_type < LOM_LOMLITE2 ? "LOMlite" : "LOMlite2",
 	    fw_rev >> 4, fw_rev & 0x0f);
 
+	TAILQ_INIT(&sc->sc_queue);
+	mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_BIO);
+
 	config2 = config3 = 0;
-	if (sc->sc_type >= LOM_LOMLITE2) {
+	if (sc->sc_type < LOM_LOMLITE2) {
+		/*
+		 * LOMlite doesn't do interrupts so we limp along on
+		 * timeouts.
+		 */
+		callout_init(&sc->sc_state_to, 0);
+		callout_setfunc(&sc->sc_state_to, lom1_process_queue, sc);
+	} else {
 		lom_read(sc, LOM_IDX_CONFIG2, &config2);
 		lom_read(sc, LOM_IDX_CONFIG3, &config3);
+
+		bus_intr_establish(sc->sc_iot, ea->ea_intr[0],
+		    IPL_BIO, lom2_intr, sc);
 	}
 
+	sc->sc_num_alarm = LOM_MAX_ALARM;
 	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);
@@ -291,6 +317,16 @@
 
 	/* Initialize sensor data. */
 	sc->sc_sme = sysmon_envsys_create();
+	for (i = 0; i < sc->sc_num_alarm; i++) {
+		sc->sc_alarm[i].units = ENVSYS_INDICATOR;
+		snprintf(sc->sc_alarm[i].desc, sizeof(sc->sc_alarm[i].desc),
+		    i == 0 ? "Fault LED" : "Alarm%d", i);
+		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_alarm[i])) {
+			sysmon_envsys_destroy(sc->sc_sme);
+			aprint_error_dev(self, "can't attach alarm sensor\n");
+			return;
+		}
+	}
 	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),
@@ -357,6 +393,9 @@
 	}
 
 	aprint_verbose_dev(self, "Watchdog timer configured.\n");
+
+	if (!pmf_device_register1(self, NULL, NULL, lom_shutdown))
+		aprint_error_dev(self, "unable to register power handler\n");
 }
 
 static int
@@ -386,6 +425,21 @@
 		return lom2_queue_cmd(sc, lc);
 }
 
+static void
+lom_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 int
 lom1_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
 {
@@ -401,7 +455,7 @@
 
 	error = tsleep(&lc, PZERO, "lomrd", hz);
 	if (error)
-		lom1_dequeue_cmd(sc, &lc);
+		lom_dequeue_cmd(sc, &lc);
 
 	*val = lc.lc_data;
 
@@ -409,7 +463,7 @@
 }
 
 static int
-lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
+lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
 {
 	struct lom_cmd lc;
 	int error;
@@ -421,9 +475,9 @@
 	lc.lc_data = val;
 	lom1_queue_cmd(sc, &lc);
 
-	error = tsleep(&lc, PZERO, "lomwr", hz);
+	error = tsleep(&lc, PZERO, "lomwr", 2 * hz);
 	if (error)
-		lom1_dequeue_cmd(sc, &lc);
+		lom_dequeue_cmd(sc, &lc);
 
 	return (error);
 }
@@ -461,7 +515,7 @@
 }
 
 static int
-lom1_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
+lom1_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
 {
 	uint8_t str;
 	int i;
@@ -507,21 +561,6 @@
 }
 
 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;
@@ -538,13 +577,26 @@
 	uint8_t str;
 
 	lc = TAILQ_FIRST(&sc->sc_queue);
-	KASSERT(lc != NULL);
+	if (lc == NULL) {
+		sc->sc_state = LOM_STATE_IDLE;
+		return;
+	}
 
 	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM1_STATUS);
 	if (str & LOM1_STATUS_BUSY) {
-		if (sc->sc_retry++ > 30)
+		if (sc->sc_retry++ < 30) {
+			callout_schedule(&sc->sc_state_to, mstohz(1));
 			return;
-		callout_schedule(&sc->sc_state_to, mstohz(1));
+		}
+
+		/*
+		 * Looks like the microcontroller got wedged.  Unwedge
+		 * it by writing this magic value.  Give it some time
+		 * to recover.
+		 */
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM1_DATA, 0xac);
+		callout_schedule(&sc->sc_state_to, mstohz(1000));
+		sc->sc_state = LOM_STATE_CMD;
 		return;
 	}
 
@@ -579,6 +631,28 @@
 static int
 lom2_read(struct lom_softc *sc, uint8_t reg, uint8_t *val)
 {
+	struct lom_cmd lc;
+	int error;
+
+	if (cold)
+		return lom2_read_polled(sc, reg, val);
+
+	lc.lc_cmd = reg;
+	lc.lc_data = 0xff;
+	lom2_queue_cmd(sc, &lc);
+
+	error = tsleep(&lc, PZERO, "lom2rd", hz);
+	if (error)
+		aprint_error_dev(sc->sc_dev, "lom2_read failed\n");
+
+	*val = lc.lc_data;
+
+	return (error);
+}
+
+static int
+lom2_read_polled(struct lom_softc *sc, uint8_t reg, uint8_t *val)
+{
 	uint8_t str;
 	int i;
 
@@ -611,6 +685,26 @@
 static int
 lom2_write(struct lom_softc *sc, uint8_t reg, uint8_t val)
 {
+	struct lom_cmd lc;
+	int error;
+
+	if (cold)
+		return lom2_write_polled(sc, reg, val);
+
+	lc.lc_cmd = reg | LOM_IDX_WRITE;
+	lc.lc_data = val;
+	lom2_queue_cmd(sc, &lc);
+
+	error = tsleep(&lc, PZERO, "lom2wr", hz);
+	if (error)
+		lom_dequeue_cmd(sc, &lc);
+
+	return (error);
+}
+
+static int
+lom2_write_polled(struct lom_softc *sc, uint8_t reg, uint8_t val)
+{
 	uint8_t str;
 	int i;
 
@@ -625,7 +719,7 @@
 		return (ETIMEDOUT);
 
 	if (sc->sc_space == LOM_IDX_CMD_GENERIC && reg != LOM_IDX_CMD)
-		reg |= 0x80;
+		reg |= LOM_IDX_WRITE;
 
 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, LOM2_CMD, reg);
 
@@ -675,8 +769,68 @@
 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);
+	uint8_t str;
+
+	mutex_enter(&sc->sc_queue_mtx);
+	TAILQ_INSERT_TAIL(&sc->sc_queue, lc, lc_next);
+	if (sc->sc_state == LOM_STATE_IDLE) {
+		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
+		if ((str & LOM2_STATUS_IBF) == 0) {
+			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+			    LOM2_CMD, lc->lc_cmd);
+			sc->sc_state = LOM_STATE_DATA;
+		}
+	}
+	mutex_exit(&sc->sc_queue_mtx);
+}
+
+static int
+lom2_intr(void *arg)
+{
+	struct lom_softc *sc = arg;
+	struct lom_cmd *lc;
+	uint8_t str, obr;
+
+	mutex_enter(&sc->sc_queue_mtx);
+
+	str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
+	obr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_DATA);
+
+	lc = TAILQ_FIRST(&sc->sc_queue);
+	if (lc == NULL) {
+		mutex_exit(&sc->sc_queue_mtx);
+		return (0);
+	}
+
+	if (lc->lc_cmd & LOM_IDX_WRITE) {
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+		    LOM2_DATA, lc->lc_data);
+		lc->lc_cmd &= ~LOM_IDX_WRITE;
+		mutex_exit(&sc->sc_queue_mtx);
+		return (1);
+	}
+
+	KASSERT(sc->sc_state = LOM_STATE_DATA);
+	lc->lc_data = obr;
+
+	TAILQ_REMOVE(&sc->sc_queue, lc, lc_next);
+
+	wakeup(lc);
+
+	sc->sc_state = LOM_STATE_IDLE;
+
+	if (!TAILQ_EMPTY(&sc->sc_queue)) {
+		str = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LOM2_STATUS);
+		if ((str & LOM2_STATUS_IBF) == 0) {
+			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+			    LOM2_CMD, lc->lc_cmd);
+			sc->sc_state = LOM_STATE_DATA;
+		}
+	}
+
+	mutex_exit(&sc->sc_queue_mtx);
+
+	return (1);
 }
 
 static int
@@ -764,6 +918,27 @@
 	uint8_t val;
 	int i;
 
+	if (lom_read(sc, LOM_IDX_ALARM, &val)) {
+		for (i = 0; i < sc->sc_num_alarm; i++)
+			sc->sc_alarm[i].state = ENVSYS_SINVALID;
+	} else {
+		/* Fault LED */
+		if ((val & LOM_ALARM_FAULT) == LOM_ALARM_FAULT)
+			sc->sc_alarm[0].value_cur = 0;
+		else
+			sc->sc_alarm[0].value_cur = 1;
+		sc->sc_alarm[0].state = ENVSYS_SVALID;
+
+		/* Alarms */
+		for (i = 1; i < sc->sc_num_alarm; i++) {
+			if ((val & (LOM_ALARM_1 << (i - 1))) == 0)
+				sc->sc_alarm[i].value_cur = 0;
+			else
+				sc->sc_alarm[i].value_cur = 1;
+			sc->sc_alarm[i].state = ENVSYS_SVALID;
+		}
+	}
+
 	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;
@@ -890,6 +1065,7 @@
 		lom_write(sc, LOM_IDX_WDOG_TIME, smw->smw_period);
 
 		/* enable watchdog */
+		lom_dequeue_cmd(sc, &sc->sc_wdog_pat);
 		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;
@@ -898,3 +1074,13 @@
 
 	return 0;
 }
+
+static bool
+lom_shutdown(device_t dev, int how)
+{
+	struct lom_softc *sc = device_private(dev);
+
+	sc->sc_wdog_ctl &= ~LOM_WDOG_ENABLE;
+	lom_write(sc, LOM_IDX_WDOG_CTL, sc->sc_wdog_ctl);
+	return true;
+}

Reply via email to