+ /*
+ * Check for and process errors on
+ * either the drive or the controller.
+ */
+ if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) {
+ waitdry = 0;
+ while ((upaddr->upds & UPDS_DRY) == 0) {
+ if (++waitdry > 512)
+ break;
+ upwaitdry++;
+ }
+ if (upaddr->uper1&UPER1_WLE) {
+ /*
+ * Give up on write locked devices
+ * immediately.
+ */
+ printf("up%d: write locked\n", dkunit(bp));
+ bp->b_flags |= B_ERROR;
+ } else if (++um->um_tab.b_errcnt > 27) {
+ /*
+ * After 28 retries (16 without offset, and
+ * 12 with offset positioning) give up.
+ */
+ harderr(bp, "up");
+ printf("cs2=%b er1=%b er2=%b\n",
+ upaddr->upcs2, UPCS2_BITS,
+ upaddr->uper1, UPER1_BITS,
+ upaddr->uper2, UPER2_BITS);
+ bp->b_flags |= B_ERROR;
+ } else {
+ /*
+ * Retriable error.
+ * If a soft ecc, correct it (continuing
+ * by returning if necessary.
+ * Otherwise fall through and retry the transfer
+ */
+ um->um_tab.b_active = 0; /* force retry */
+ if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK)
+ if (upecc(ui))
+ return;
+ }
+ /*
+ * Clear drive error and, every eight attempts,
+ * (starting with the fourth)
+ * recalibrate to clear the slate.
+ */
+ upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
+ needie = 0;
+ if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) {
+ upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
+ sc->sc_recal = 0;
+ goto nextrecal;
+ }
+ }
+ /*
+ * Advance recalibration finite state machine
+ * if recalibrate in progress, through
+ * RECAL
+ * SEEK
+ * OFFSET (optional)
+ * RETRY
+ */
+ switch (sc->sc_recal) {
+
+ case 1:
+ upaddr->updc = bp->b_cylin;
+ upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO;
+ goto nextrecal;
+ case 2:
+ if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0)
+ goto donerecal;
+ upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22;
+ upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
+ goto nextrecal;
+ nextrecal:
+ sc->sc_recal++;
+ um->um_tab.b_active = 1;
+ return;
+ donerecal:
+ case 3:
+ sc->sc_recal = 0;
+ um->um_tab.b_active = 0;
+ break;
+ }
+ /*
+ * If still ``active'', then don't need any more retries.
+ */
+ if (um->um_tab.b_active) {
+ /*
+ * If we were offset positioning,
+ * return to centerline.
+ */
+ if (um->um_tab.b_errcnt >= 16) {
+ upaddr->upof = UPOF_FMT22;
+ upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
+ while (upaddr->upds & UPDS_PIP)