+
+/*
+ * Reset the controller.
+ */
+static int
+wdreset(struct disk *du)
+{
+ int wdc;
+
+ wdc = du->dk_port;
+ (void)wdwait(du, 0, TIMEOUT);
+ outb(wdc + wd_ctlr, WDCTL_IDS | WDCTL_RST);
+ DELAY(10 * 1000);
+ outb(wdc + wd_ctlr, WDCTL_IDS);
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
+ || (du->dk_error = inb(wdc + wd_error)) != 0x01)
+ return (1);
+ outb(wdc + wd_ctlr, WDCTL_4BIT);
+ return (0);
+}
+
+/*
+ * Sleep until driver is inactive.
+ * This is used only for avoiding rare race conditions, so it is unimportant
+ * that the sleep may be far too short or too long.
+ */
+static void
+wdsleep(int ctrlr, char *wmesg)
+{
+ while (wdtab[ctrlr].b_active)
+ tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
+}
+
+static void
+wdtimeout(caddr_t cdu, int ticks)
+{
+ struct disk *du;
+ int x;
+
+ du = (struct disk *)cdu;
+ x = splbio();
+ if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
+ wderror((struct buf *)NULL, du, "interrupt timeout");
+ wdunwedge(du);
+ wdflushirq(du, x);
+ du->dk_skip = 0;
+ du->dk_flags |= DKFL_SINGLE;
+ wdstart(du->dk_ctrlr);
+ }
+ timeout(wdtimeout, cdu, hz);
+ splx(x);
+}
+
+/*
+ * Reset the controller after it has become wedged. This is different from
+ * wdreset() so that wdreset() can be used in the probe and so that this
+ * can restore the geometry .
+ */
+static int
+wdunwedge(struct disk *du)
+{
+ struct disk *du1;
+ int lunit;
+
+ /* Schedule other drives for recalibration. */
+ for (lunit = 0; lunit < NWD; lunit++)
+ if ((du1 = wddrives[lunit]) != NULL && du1 != du
+ && du1->dk_ctrlr == du->dk_ctrlr
+ && du1->dk_state > WANTOPEN)
+ du1->dk_state = WANTOPEN;
+
+ DELAY(RECOVERYTIME);
+ if (wdreset(du) == 0) {
+ /*
+ * XXX - recalibrate current drive now because some callers
+ * aren't prepared to have its state change.
+ */
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
+ && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
+ && wdsetctlr(du) == 0)
+ return (0);
+ }
+ wderror((struct buf *)NULL, du, "wdunwedge failed");
+ return (1);
+}
+
+/*
+ * Wait uninterruptibly until controller is not busy and either certain
+ * status bits are set or an error has occurred.
+ * The wait is usually short unless it is for the controller to process
+ * an entire critical command.
+ * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
+ * or 0 for no errors.
+ * Return controller status in du->dk_status and, if there was a controller
+ * error, return the error code in du->dk_error.
+ */
+#ifdef WD_COUNT_RETRIES
+static int min_retries[NWDC];