static void fdc_conf(struct fdc_softc *fdc) { bus_space_tag_t iot = fdc->sc_iot; bus_space_handle_t ioh = fdc->sc_ioh; int n; /* Figure out what we have */ if (out_fdc_cmd(iot, ioh, FDC_CMD_VERSION) == -1 || (n = fdcresult(fdc, 1)) != 1) return; /* Nec765 or equivalent */ if (FDC_ST0(fdc->sc_status[0]) == FDC_ST0_INVL) return; #if 0 /* ns8477 check */ if (out_fdc_cmd(iot, ioh, FDC_CMD_NSC) == -1 || (n = fdcresult(fdc, 1)) != 1) { printf("NSC command failed\n"); return; } else printf("Version %x\n", fdc->sc_status[0]); #endif if (out_fdc_cmd(iot, ioh, FDC_CMD_DUMPREG) == -1 || (n = fdcresult(fdc, -1)) == -1) return; /* * Expect 10 bytes of status; one means that it did not * understand the command */ if (n == 1) return; /* * Configure controller to use FIFO and 8 bytes of FIFO threshold */ (void)out_fdc_cmd(iot, ioh, FDC_CMD_CONFIGURE); (void)out_fdc(iot, ioh, 0x00); /* doc says 0 */ (void)out_fdc(iot, ioh, 8); /* FIFO is active low. */ (void)out_fdc(iot, ioh, fdc->sc_status[9]); /* same comp */ /* No result phase */ /* Lock this configuration */ if (out_fdc_cmd(iot, ioh, FDC_CMD_LOCK(FDC_CMD_FLAGS_LOCK)) == -1 || fdcresult(fdc, 1) != 1) return; }
int fdprobe(struct device *parent, void *match, void *aux) { struct fdc_softc *fdc = (void *)parent; struct cfdata *cf = match; struct fdc_attach_args *fa = aux; int drive = fa->fa_drive; bus_space_tag_t iot = fdc->sc_iot; bus_space_handle_t ioh = fdc->sc_ioh; int n; if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive) return 0; /* * XXX * This is to work around some odd interactions between this driver * and SMC Ethernet cards. */ if (cf->cf_loc[0] == -1 && drive >= 2) return 0; /* * We want to keep the flags config gave us. */ fa->fa_flags = cf->cf_flags; /* select drive and turn on motor */ bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); /* wait for motor to spin up */ delay(250000); out_fdc(iot, ioh, NE7CMD_RECAL); out_fdc(iot, ioh, drive); /* wait for recalibrate */ delay(2000000); out_fdc(iot, ioh, NE7CMD_SENSEI); n = fdcresult(fdc); #ifdef FD_DEBUG { int i; printf("fdprobe: status"); for (i = 0; i < n; i++) printf(" %x", fdc->sc_status[i]); printf("\n"); } #endif /* turn off motor */ delay(250000); bus_space_write_1(iot, ioh, fdout, FDO_FRST); /* flags & 0x20 forces the drive to be found even if it won't probe */ if (!(fa->fa_flags & 0x20) && (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)) return 0; return 1; }
void fdcstatus(device_t dv, int n, const char *s) { struct fdc_softc *fdc = device_private(device_parent(dv)); char bits[64]; if (n == 0) { out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); (void) fdcresult(fdc); n = 2; } aprint_normal_dev(dv, "%s", s); switch (n) { case 0: printf("\n"); break; case 2: printf(" (st0 %s cyl %d)\n", bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, bits, sizeof(bits)), fdc->sc_status[1]); break; case 7: printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, bits, sizeof(bits))); printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], NE7_ST1BITS, bits, sizeof(bits))); printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], NE7_ST2BITS, bits, sizeof(bits))); printf(" cyl %d head %d sec %d)\n", fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); break; #ifdef DIAGNOSTIC default: printf("\nfdcstatus: weird size"); break; #endif } }
void fdcstatus(struct device *dv, int n, char *s) { struct fdc_softc *fdc = (void *)dv->dv_parent; if (n == 0) { out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); (void) fdcresult(fdc); n = 2; } printf("%s: %s", dv->dv_xname, s); switch (n) { case 0: printf("\n"); break; case 2: printf(" (st0 %b cyl %d)\n", fdc->sc_status[0], NE7_ST0BITS, fdc->sc_status[1]); break; case 7: printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", fdc->sc_status[0], NE7_ST0BITS, fdc->sc_status[1], NE7_ST1BITS, fdc->sc_status[2], NE7_ST2BITS, fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); break; #ifdef DIAGNOSTIC default: printf("\nfdcstatus: weird size"); break; #endif } }
int fdprobe(device_t parent, cfdata_t match, void *aux) { struct fdc_softc *fdc = device_private(parent); struct cfdata *cf = match; struct fdc_attach_args *fa = aux; int drive = fa->fa_drive; bus_space_tag_t iot = fdc->sc_iot; bus_space_handle_t ioh = fdc->sc_ioh; int n; if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT && cf->cf_loc[FDCCF_DRIVE] != drive) return 0; /* * XXX * This is to work around some odd interactions between this driver * and SMC Ethernet cards. */ if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) return 0; /* Use PNP information if available */ if (fdc->sc_known) return 1; mutex_enter(&fdc->sc_mtx); /* toss any interrupt status */ for (n = 0; n < 4; n++) { out_fdc(iot, ioh, NE7CMD_SENSEI); (void) fdcresult(fdc); } /* select drive and turn on motor */ bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); /* wait for motor to spin up */ /* XXX check sc_probe */ (void) cv_timedwait(&fdc->sc_cv, &fdc->sc_mtx, hz / 4); out_fdc(iot, ioh, NE7CMD_RECAL); out_fdc(iot, ioh, drive); /* wait for recalibrate, up to 2s */ /* XXX check sc_probe */ if (cv_timedwait(&fdc->sc_cv, &fdc->sc_mtx, 2 * hz) != EWOULDBLOCK){ #ifdef FD_DEBUG /* XXX */ printf("fdprobe: got intr\n"); #endif } out_fdc(iot, ioh, NE7CMD_SENSEI); n = fdcresult(fdc); #ifdef FD_DEBUG { int i; printf("fdprobe: status"); for (i = 0; i < n; i++) printf(" %x", fdc->sc_status[i]); printf("\n"); } #endif /* turn off motor */ bus_space_write_1(iot, ioh, fdout, FDO_FRST); mutex_exit(&fdc->sc_mtx); #if defined(bebox) /* XXX What is this about? [email protected] */ if (n != 2 || (fdc->sc_status[1] != 0)) return 0; #else if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) return 0; #endif /* bebox */ return 1; }
static int fdcintr1(struct fdc_softc *fdc) { #define st0 fdc->sc_status[0] #define cyl fdc->sc_status[1] struct fd_softc *fd; struct buf *bp; bus_space_tag_t iot = fdc->sc_iot; bus_space_handle_t ioh = fdc->sc_ioh; int read, head, sec, i, nblks; struct fd_type *type; struct ne7_fd_formb *finfo = NULL; KASSERT(mutex_owned(&fdc->sc_mtx)); if (fdc->sc_state == PROBING) { #ifdef DEBUG printf("fdcintr: got probe interrupt\n"); #endif fdc->sc_probe++; goto out; } loop: /* Is there a drive for the controller to do a transfer with? */ fd = TAILQ_FIRST(&fdc->sc_drives); if (fd == NULL) { fdc->sc_state = DEVIDLE; goto out; } /* Is there a transfer to this drive? If not, deactivate drive. */ bp = BUFQ_PEEK(fd->sc_q); if (bp == NULL) { fd->sc_ops = 0; TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); fd->sc_active = 0; goto loop; } if (bp->b_flags & B_FORMAT) finfo = (struct ne7_fd_formb *)bp->b_data; switch (fdc->sc_state) { case DEVIDLE: fdc->sc_errors = 0; fd->sc_skip = 0; fd->sc_bcount = bp->b_bcount; fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); callout_stop(&fd->sc_motoroff_ch); if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { fdc->sc_state = MOTORWAIT; return 1; } if ((fd->sc_flags & FD_MOTOR) == 0) { /* Turn on the motor, being careful about pairing. */ struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; if (ofd && ofd->sc_flags & FD_MOTOR) { callout_stop(&ofd->sc_motoroff_ch); ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); } fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; fd_set_motor(fdc, 0); fdc->sc_state = MOTORWAIT; /* Allow .25s for motor to stabilize. */ callout_reset(&fd->sc_motoron_ch, hz / 4, fd_motor_on, fd); return 1; } /* Make sure the right drive is selected. */ fd_set_motor(fdc, 0); /* fall through */ case DOSEEK: doseek: if (fd->sc_cylin == bp->b_cylinder) goto doio; out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ out_fdc(iot, ioh, fd->sc_type->steprate); out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ out_fdc(iot, ioh, fd->sc_drive); /* drive number */ out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); fd->sc_cylin = -1; fdc->sc_state = SEEKWAIT; iostat_seek(fd->sc_dk.dk_stats); disk_busy(&fd->sc_dk); callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); return 1; case DOIO: doio: type = fd->sc_type; if (finfo) fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - (char *)finfo; sec = fd->sc_blkno % type->seccyl; nblks = type->seccyl - sec; nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE); fd->sc_nblks = nblks; fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; head = sec / type->sectrac; sec -= head * type->sectrac; #ifdef DIAGNOSTIC { int block; block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; if (block != fd->sc_blkno) { printf("fdcintr: block %d != blkno " "%" PRId64 "\n", block, fd->sc_blkno); #ifdef DDB Debugger(); #endif } } #endif read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE; isa_dmastart(fdc->sc_ic, fdc->sc_drq, (char *)bp->b_data + fd->sc_skip, fd->sc_nbytes, NULL, read | DMAMODE_DEMAND, BUS_DMA_NOWAIT); bus_space_write_1(iot, fdc->sc_fdctlioh, 0, type->rate); #ifdef FD_DEBUG printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head, sec, nblks); #endif if (finfo) { /* formatting */ if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { fdc->sc_errors = 4; fdcretry(fdc); goto loop; } out_fdc(iot, ioh, (head << 2) | fd->sc_drive); out_fdc(iot, ioh, finfo->fd_formb_secshift); out_fdc(iot, ioh, finfo->fd_formb_nsecs); out_fdc(iot, ioh, finfo->fd_formb_gaplen); out_fdc(iot, ioh, finfo->fd_formb_fillbyte); } else { if (read) out_fdc(iot, ioh, NE7CMD_READ); /* READ */ else out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ out_fdc(iot, ioh, (head << 2) | fd->sc_drive); out_fdc(iot, ioh, fd->sc_cylin); /* track */ out_fdc(iot, ioh, head); out_fdc(iot, ioh, sec + 1); /* sector +1 */ out_fdc(iot, ioh, type->secsize);/* sector size */ out_fdc(iot, ioh, type->sectrac);/* sectors/track */ out_fdc(iot, ioh, type->gap1); /* gap1 size */ out_fdc(iot, ioh, type->datalen);/* data length */ } fdc->sc_state = IOCOMPLETE; disk_busy(&fd->sc_dk); /* allow 2 seconds for operation */ callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); return 1; /* will return later */ case SEEKWAIT: callout_stop(&fdc->sc_timo_ch); fdc->sc_state = SEEKCOMPLETE; /* allow 1/50 second for heads to settle */ callout_reset(&fdc->sc_intr_ch, hz / 50, fdcintrcb, fdc); return 1; case SEEKCOMPLETE: /* no data on seek */ disk_unbusy(&fd->sc_dk, 0, 0); /* Make sure seek really happened. */ out_fdc(iot, ioh, NE7CMD_SENSEI); if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != bp->b_cylinder * fd->sc_type->step) { #ifdef FD_DEBUG fdcstatus(fd->sc_dev, 2, "seek failed"); #endif fdcretry(fdc); goto loop; } fd->sc_cylin = bp->b_cylinder; goto doio; case IOTIMEDOUT: isa_dmaabort(fdc->sc_ic, fdc->sc_drq); case SEEKTIMEDOUT: case RECALTIMEDOUT: case RESETTIMEDOUT: fdcretry(fdc); goto loop; case IOCOMPLETE: /* IO DONE, post-analyze */ callout_stop(&fdc->sc_timo_ch); disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), (bp->b_flags & B_READ)); if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { isa_dmaabort(fdc->sc_ic, fdc->sc_drq); #ifdef FD_DEBUG fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ? "read failed" : "write failed"); printf("blkno %llu nblks %d\n", (unsigned long long)fd->sc_blkno, fd->sc_nblks); #endif fdcretry(fdc); goto loop; } isa_dmadone(fdc->sc_ic, fdc->sc_drq); if (fdc->sc_errors) { diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, fd->sc_skip / FDC_BSIZE, NULL); printf("\n"); fdc->sc_errors = 0; } fd->sc_blkno += fd->sc_nblks; fd->sc_skip += fd->sc_nbytes; fd->sc_bcount -= fd->sc_nbytes; if (!finfo && fd->sc_bcount > 0) { bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; goto doseek; } fdfinish(fd, bp); goto loop; case DORESET: /* try a reset, keep motor on */ fd_set_motor(fdc, 1); delay(100); fd_set_motor(fdc, 0); fdc->sc_state = RESETCOMPLETE; callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); return 1; /* will return later */ case RESETCOMPLETE: callout_stop(&fdc->sc_timo_ch); /* clear the controller output buffer */ for (i = 0; i < 4; i++) { out_fdc(iot, ioh, NE7CMD_SENSEI); (void) fdcresult(fdc); } /* fall through */ case DORECAL: out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ out_fdc(iot, ioh, fd->sc_drive); fdc->sc_state = RECALWAIT; callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); return 1; /* will return later */ case RECALWAIT: callout_stop(&fdc->sc_timo_ch); fdc->sc_state = RECALCOMPLETE; /* allow 1/30 second for heads to settle */ callout_reset(&fdc->sc_intr_ch, hz / 30, fdcintrcb, fdc); return 1; /* will return later */ case RECALCOMPLETE: out_fdc(iot, ioh, NE7CMD_SENSEI); if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { #ifdef FD_DEBUG fdcstatus(fd->sc_dev, 2, "recalibrate failed"); #endif fdcretry(fdc); goto loop; } fd->sc_cylin = 0; goto doseek; case MOTORWAIT: if (fd->sc_flags & FD_MOTOR_WAIT) return 1; /* time's not up yet */ goto doseek; default: fdcstatus(fd->sc_dev, 0, "stray interrupt"); return 1; } #undef st0 #undef cyl out: cv_signal(&fdc->sc_cv); return 1; }
/* * Called from the controller. */ int fdintr(struct fdc_softc *fdc) { #define st0 fdc->sc_status[0] #define cyl fdc->sc_status[1] struct fd_softc *fd; struct buf *bp; bus_space_tag_t iot = fdc->sc_iot; bus_space_handle_t ioh = fdc->sc_ioh; bus_space_handle_t ioh_ctl = fdc->sc_ioh_ctl; int read, head, sec, i, nblks, cylin; struct fd_type *type; struct fd_formb *finfo = NULL; int fd_bsize; loop: /* Is there a transfer to this drive? If not, deactivate drive. */ fd = TAILQ_FIRST(&fdc->sc_link.fdlink.sc_drives); if (fd == NULL) { fdc->sc_state = DEVIDLE; return 1; } fd_bsize = FD_BSIZE(fd); bp = fd->sc_bp; if (bp == NULL) { fd->sc_ops = 0; TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain); goto loop; } if (bp->b_flags & B_FORMAT) finfo = (struct fd_formb *)bp->b_data; cylin = ((bp->b_blkno * DEV_BSIZE) + (bp->b_bcount - bp->b_resid)) / (fd_bsize * fd->sc_type->seccyl); switch (fdc->sc_state) { case DEVIDLE: fdc->sc_errors = 0; fd->sc_skip = 0; fd->sc_bcount = bp->b_bcount; fd->sc_blkno = bp->b_blkno / (fd_bsize / DEV_BSIZE); timeout_del(&fd->fd_motor_off_to); if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { fdc->sc_state = MOTORWAIT; return 1; } if ((fd->sc_flags & FD_MOTOR) == 0) { /* Turn on the motor, being careful about pairing. */ struct fd_softc *ofd = fdc->sc_link.fdlink.sc_fd[fd->sc_drive ^ 1]; if (ofd && ofd->sc_flags & FD_MOTOR) { timeout_del(&ofd->fd_motor_off_to); ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); } fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; fd_set_motor(fdc, 0); fdc->sc_state = MOTORWAIT; /* Allow .25s for motor to stabilize. */ timeout_add_msec(&fd->fd_motor_on_to, 250); return 1; } /* Make sure the right drive is selected. */ fd_set_motor(fdc, 0); /* FALLTHROUGH */ case DOSEEK: doseek: if (fd->sc_cylin == cylin) goto doio; out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ out_fdc(iot, ioh, fd->sc_type->steprate); out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ out_fdc(iot, ioh, fd->sc_drive); /* drive number */ out_fdc(iot, ioh, cylin * fd->sc_type->step); fd->sc_cylin = -1; fdc->sc_state = SEEKWAIT; fd->sc_dk.dk_seek++; disk_busy(&fd->sc_dk); timeout_add_sec(&fd->fdtimeout_to, 4); return 1; case DOIO: doio: type = fd->sc_type; if (finfo) fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - (char *)finfo; sec = fd->sc_blkno % type->seccyl; nblks = type->seccyl - sec; nblks = min(nblks, fd->sc_bcount / fd_bsize); nblks = min(nblks, FDC_MAXIOSIZE / fd_bsize); fd->sc_nblks = nblks; fd->sc_nbytes = finfo ? bp->b_bcount : nblks * fd_bsize; head = sec / type->sectrac; sec -= head * type->sectrac; #ifdef DIAGNOSTIC {int block; block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; if (block != fd->sc_blkno) { panic("fdintr: block %d != blkno %llu", block, fd->sc_blkno); }} #endif read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE; isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes, fdc->sc_drq, read); bus_space_write_1(iot, ioh_ctl, fdctl, type->rate); #ifdef FD_DEBUG printf("fdintr: %s drive %d track %d head %d sec %d nblks %d\n", read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head, sec, nblks); #endif if (finfo) { /* formatting */ if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { fdc->sc_errors = 4; fdretry(fd); goto loop; } out_fdc(iot, ioh, (head << 2) | fd->sc_drive); out_fdc(iot, ioh, finfo->fd_formb_secshift); out_fdc(iot, ioh, finfo->fd_formb_nsecs); out_fdc(iot, ioh, finfo->fd_formb_gaplen); out_fdc(iot, ioh, finfo->fd_formb_fillbyte); } else { if (read) out_fdc(iot, ioh, NE7CMD_READ); /* READ */ else out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */ out_fdc(iot, ioh, (head << 2) | fd->sc_drive); out_fdc(iot, ioh, fd->sc_cylin); /* track */ out_fdc(iot, ioh, head); out_fdc(iot, ioh, sec + 1); /* sec +1 */ out_fdc(iot, ioh, type->secsize); /* sec size */ out_fdc(iot, ioh, type->sectrac); /* secs/track */ out_fdc(iot, ioh, type->gap1); /* gap1 size */ out_fdc(iot, ioh, type->datalen); /* data len */ } fdc->sc_state = IOCOMPLETE; disk_busy(&fd->sc_dk); /* allow 2 seconds for operation */ timeout_add_sec(&fd->fdtimeout_to, 2); return 1; /* will return later */ case SEEKWAIT: timeout_del(&fd->fdtimeout_to); fdc->sc_state = SEEKCOMPLETE; /* allow 1/50 second for heads to settle */ timeout_add_msec(&fdc->fdcpseudointr_to, 20); return 1; case SEEKCOMPLETE: disk_unbusy(&fd->sc_dk, 0, 0); /* no data on seek */ /* Make sure seek really happened. */ out_fdc(iot, ioh, NE7CMD_SENSEI); if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != cylin * fd->sc_type->step) { #ifdef FD_DEBUG fdcstatus(&fd->sc_dev, 2, "seek failed"); #endif fdretry(fd); goto loop; } fd->sc_cylin = cylin; goto doio; case IOTIMEDOUT: isadma_abort(fdc->sc_drq); case SEEKTIMEDOUT: case RECALTIMEDOUT: case RESETTIMEDOUT: fdretry(fd); goto loop; case IOCOMPLETE: /* IO DONE, post-analyze */ timeout_del(&fd->fdtimeout_to); disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), (bp->b_flags & B_READ)); if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { isadma_abort(fdc->sc_drq); #ifdef FD_DEBUG fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? "read failed" : "write failed"); printf("blkno %lld nblks %d\n", (long long)fd->sc_blkno, fd->sc_nblks); #endif fdretry(fd); goto loop; } read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE; isadma_done(fdc->sc_drq); if (fdc->sc_errors) { diskerr(bp, "fd", "soft error", LOG_PRINTF, fd->sc_skip / fd_bsize, (struct disklabel *)NULL); printf("\n"); fdc->sc_errors = 0; } fd->sc_blkno += fd->sc_nblks; fd->sc_skip += fd->sc_nbytes; fd->sc_bcount -= fd->sc_nbytes; bp->b_resid -= fd->sc_nbytes; if (!finfo && fd->sc_bcount > 0) { cylin = fd->sc_blkno / fd->sc_type->seccyl; goto doseek; } fdfinish(fd, bp); goto loop; case DORESET: /* try a reset, keep motor on */ fd_set_motor(fdc, 1); delay(100); fd_set_motor(fdc, 0); fdc->sc_state = RESETCOMPLETE; timeout_add_msec(&fd->fdtimeout_to, 500); return 1; /* will return later */ case RESETCOMPLETE: timeout_del(&fd->fdtimeout_to); /* clear the controller output buffer */ for (i = 0; i < 4; i++) { out_fdc(iot, ioh, NE7CMD_SENSEI); (void) fdcresult(fdc); } /* FALLTHROUGH */ case DORECAL: out_fdc(iot, ioh, NE7CMD_RECAL); /* recal function */ out_fdc(iot, ioh, fd->sc_drive); fdc->sc_state = RECALWAIT; timeout_add_sec(&fd->fdtimeout_to, 5); return 1; /* will return later */ case RECALWAIT: timeout_del(&fd->fdtimeout_to); fdc->sc_state = RECALCOMPLETE; /* allow 1/30 second for heads to settle */ timeout_add(&fdc->fdcpseudointr_to, hz / 30); return 1; /* will return later */ case RECALCOMPLETE: out_fdc(iot, ioh, NE7CMD_SENSEI); if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { #ifdef FD_DEBUG fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); #endif fdretry(fd); goto loop; } fd->sc_cylin = 0; goto doseek; case MOTORWAIT: if (fd->sc_flags & FD_MOTOR_WAIT) return 1; /* time's not up yet */ goto doseek; default: fdcstatus(&fd->sc_dev, 0, "stray interrupt"); return 1; } #ifdef DIAGNOSTIC panic("fdintr: impossible"); #endif #undef st0 #undef cyl }