+
+bad:
+ m_freem(m0);
+ return (error);
+}
+
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+dmcioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ int s = splimp(), error = 0;
+ register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ dmcinit(ifp->if_unit);
+ break;
+
+ case SIOCSIFDSTADDR:
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ dmcinit(ifp->if_unit);
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ sc->sc_flag & DMC_RUNNING)
+ dmcdown(ifp->if_unit);
+ else if (ifp->if_flags & IFF_UP &&
+ (sc->sc_flag & DMC_RUNNING) == 0)
+ dmcrestart(ifp->if_unit);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+
+/*
+ * Restart after a fatal error.
+ * Clear device and reinitialize.
+ */
+dmcrestart(unit)
+ int unit;
+{
+ register struct dmc_softc *sc = &dmc_softc[unit];
+ register struct dmcdevice *addr;
+ register int i;
+ int s;
+
+#ifdef DEBUG
+ /* dump base table */
+ printf("dmc%d base table:\n", unit);
+ for (i = 0; i < sizeof (struct dmc_base); i++)
+ printf("%o\n" ,dmc_base[unit].d_base[i]);
+#endif
+
+ dmcdown(unit);
+
+ /*
+ * Let the DMR finish the MCLR. At 1 Mbit, it should do so
+ * in about a max of 6.4 milliseconds with diagnostics enabled.
+ */
+ addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
+ for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
+ ;
+ /* Did the timer expire or did the DMR finish? */
+ if ((addr->bsel1 & DMC_RUN) == 0) {
+ log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
+ return;
+ }
+
+ /* restart DMC */
+ dmcinit(unit);
+ sc->sc_flag &= ~DMC_RESTART;
+ s = spl5();
+ dmcstart(unit);
+ splx(s);
+ sc->sc_if.if_collisions++; /* why not? */
+}
+
+/*
+ * Reset a device and mark down.
+ * Flush output queue and drop queue limit.
+ */
+dmcdown(unit)
+ int unit;
+{
+ register struct dmc_softc *sc = &dmc_softc[unit];
+ register struct ifxmt *ifxp;
+
+ ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
+ sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
+
+ for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
+ if (ifxp->ifw_xtofree) {
+ (void) m_freem(ifxp->ifw_xtofree);
+ ifxp->ifw_xtofree = 0;
+ }
+ }
+ if_qflush(&sc->sc_if.if_snd);
+}
+
+/*
+ * Watchdog timeout to see that transmitted packets don't
+ * lose interrupts. The device has to be online (the first
+ * transmission may block until the other side comes up).
+ */
+dmctimeout(unit)
+ int unit;
+{
+ register struct dmc_softc *sc;
+ struct dmcdevice *addr;
+
+ sc = &dmc_softc[unit];
+ if (sc->sc_flag & DMC_ONLINE) {
+ addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
+ log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
+ unit, addr->bsel0 & 0xff, DMC0BITS,
+ addr->bsel2 & 0xff, DMC2BITS);
+ dmcrestart(unit);
+ }