Subject: Re: wi0: record read mismatch, rid=fd42, got=fd41
To: Kurt Schreiner <ks@ub.uni-mainz.de>
From: David Young <dyoung@pobox.com>
List: current-users
Date: 09/27/2004 19:50:31
--lMM8JwqTlfDpEaS6
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Sep 27, 2004 at 03:48:44PM +0200, Kurt Schreiner wrote:
> Sep 27 15:13:59 imega-bsd /netbsd: wi0: record read mismatch, rid=fd42, got=fd41
> Sep 27 15:13:59 imega-bsd /netbsd: wi0: record read mismatch, rid=fdc1, got=fd42
> Sep 27 15:13:59 imega-bsd /netbsd: panic: wi0: invalid channel 49170
> Sep 27 15:14:00 imega-bsd /netbsd: 
> Sep 27 15:14:00 imega-bsd /netbsd: syncing disks... wi0: record read mismatch, rid=fd42, got=fdc1
> Sep 27 15:14:00 imega-bsd /netbsd: wi0: record read mismatch, rid=fdc1, got=fd42
> Sep 27 15:14:00 imega-bsd /netbsd: panic: wi0: invalid channel 0

Sometimes I see this, too.  Does it happen very often?

Try the attached patch.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--lMM8JwqTlfDpEaS6
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=wi-patch

Index: sys/dev/ic/wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.187
diff -u -r1.187 wi.c
--- sys/dev/ic/wi.c	28 Sep 2004 00:42:11 -0000	1.187
+++ sys/dev/ic/wi.c	28 Sep 2004 00:47:00 -0000
@@ -145,6 +145,7 @@
 #endif
 
 #include <machine/bus.h>
+#include <machine/stdarg.h>
 
 #include <dev/ic/wi_ieee.h>
 #include <dev/ic/wireg.h>
@@ -848,8 +849,10 @@
 
 	if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
 	    ic->ic_opmode == IEEE80211_M_MONITOR ||
-	    ic->ic_opmode == IEEE80211_M_HOSTAP)
-		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+	    ic->ic_opmode == IEEE80211_M_HOSTAP) {
+		if ((error = ieee80211_new_state(ic, IEEE80211_S_RUN, -1)) != 0)
+			goto out;
+	}
 
 	/* Enable interrupts */
 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
@@ -899,7 +902,10 @@
 
 	DPRINTF(("wi_stop: disable %d\n", disable));
 
-	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+	if (ieee80211_new_state(ic, IEEE80211_S_INIT, -1) != 0) {
+		printf("%s: wi_stop failed ->INIT\n", ifp->if_xname);
+		return;
+	}
 	if (!sc->sc_invalid) {
 		CSR_WRITE_2(sc, WI_INT_EN, 0);
 		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
@@ -1210,6 +1216,29 @@
 	return 0;
 }
 
+/* Kick the hardware (hard!) as a last-ditch effort to restore sanity. */
+STATIC void
+wi_kick(struct ifnet *ifp, const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	printf("%s: kicking, ", ifp->if_xname);
+	vprintf(fmt, ap);
+	printf("\n");
+
+	va_end(ap);
+
+	wi_stop(ifp, 1);
+	if ((rc = wi_init(ifp)) != 0) {
+		printf("%s: kick failed (%d), interface not running\n",
+		    ifp->if_xname, rc);
+		wi_stop(ifp, 1);
+	}
+}
+
 STATIC void
 wi_watchdog(struct ifnet *ifp)
 {
@@ -1435,6 +1464,7 @@
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_node *ni = ic->ic_bss;
 	struct ifnet *ifp = &ic->ic_if;
+	int rc;
 
 	if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
 		return;
@@ -1451,7 +1481,8 @@
 	                 WI_MAX_FALSE_SYNS))
 		return;
 
-	ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+	if ((rc = ieee80211_new_state(ic, IEEE80211_S_RUN, -1)) != 0)
+		wi_kick(ifp, "%s failed RUN->RUN (%d)", __func__, rc);
 }
 
 static __inline void
@@ -1806,7 +1837,7 @@
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = &ic->ic_if;
-	int i, fid, len, off;
+	int i, fid, len, off, rc;
 	u_int16_t ltbuf[2];
 	u_int16_t stat;
 	u_int32_t *ptr;
@@ -1827,7 +1858,11 @@
 				break;
 			/* FALLTHROUGH */
 		case AP_CHANGE:
-			ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+			rc = ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+			if (rc != 0) {
+				wi_kick(ifp, "%s AP change, failed "
+				    "RUN->RUN (%d)", __func__, rc);
+			}
 			break;
 		case AP_IN_RANGE:
 			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
@@ -1845,8 +1880,13 @@
 			break;
 		case DISCONNECTED:
 		case ASSOC_FAILED:
-			if (ic->ic_opmode == IEEE80211_M_STA)
-				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+			if (ic->ic_opmode != IEEE80211_M_STA)
+				break;
+			rc = ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+			if (rc != 0) {
+				wi_kick(ifp, "%s disconnected/assoc-failed, "
+				    "failed ->INIT (%d)", __func__, rc);
+			}
 			break;
 		}
 		break;
@@ -2840,7 +2880,7 @@
 	struct ifnet *ifp = &ic->ic_if;
 	struct wi_softc *sc = ic->ic_softc;
 	struct ieee80211_node *ni = ic->ic_bss;
-	int buflen, linkstate = LINK_STATE_DOWN, s;
+	int buflen, chan, linkstate = LINK_STATE_DOWN, rc, s;
 	u_int16_t val;
 	struct wi_ssid ssid;
 	struct wi_macaddr bssid, old_bssid;
@@ -2864,17 +2904,24 @@
 	case IEEE80211_S_RUN:
 		linkstate = LINK_STATE_UP;
 		sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
-		buflen = IEEE80211_ADDR_LEN;
 		IEEE80211_ADDR_COPY(old_bssid.wi_mac_addr, ni->ni_bssid);
-		wi_read_rid(sc, WI_RID_CURRENT_BSSID, &bssid, &buflen);
+		buflen = IEEE80211_ADDR_LEN;
+		if ((rc = wi_read_rid(sc, WI_RID_CURRENT_BSSID, &bssid,
+		    &buflen)) != 0)
+			return rc;
 		IEEE80211_ADDR_COPY(ni->ni_bssid, &bssid);
 		IEEE80211_ADDR_COPY(ni->ni_macaddr, &bssid);
 		buflen = sizeof(val);
-		wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
-		if (!isset(ic->ic_chan_avail, le16toh(val)))
-			panic("%s: invalid channel %d\n", sc->sc_dev.dv_xname,
-			    le16toh(val));
-		ni->ni_chan = &ic->ic_channels[le16toh(val)];
+		if ((rc = wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val,
+		    &buflen)) != 0)
+			return rc;
+		chan = le16toh(val);
+		if (!isset(ic->ic_chan_avail, chan)) {
+			printf("%s: invalid channel %d\n", sc->sc_dev.dv_xname,
+			    chan);
+			return -1;
+		}
+		ni->ni_chan = &ic->ic_channels[chan];
 
 		/* If not equal, then discount a false synchronization. */
 		if (!IEEE80211_ADDR_EQ(old_bssid.wi_mac_addr, ni->ni_bssid))
@@ -2891,7 +2938,9 @@
 				ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
 		} else {
 			buflen = sizeof(ssid);
-			wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen);
+			if ((rc = wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid,
+			    &buflen) != 0))
+				return rc;
 			ni->ni_esslen = le16toh(ssid.wi_len);
 			if (ni->ni_esslen > IEEE80211_NWID_LEN)
 				ni->ni_esslen = IEEE80211_NWID_LEN;	/*XXX*/

--lMM8JwqTlfDpEaS6--