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--