void lddone(struct ld_softc *sc, struct buf *bp) { if ((bp->b_flags & B_ERROR) != 0) { diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label); printf("\n"); } disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid); #if NRND > 0 rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno); #endif biodone(bp); if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { if ((sc->sc_flags & LDF_DRAIN) != 0) wakeup(&sc->sc_queuecnt); while ((bp = BUFQ_FIRST(&sc->sc_bufq)) != NULL) { BUFQ_REMOVE(&sc->sc_bufq, bp); if (!ldstart(sc, bp)) break; } } }
void wddone(void *v) { struct wd_softc *wd = v; struct buf *bp = wd->sc_bp; char buf[256], *errbuf = buf; WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname), DEBUG_XFERS); bp->b_resid = wd->sc_wdc_bio.bcount; errbuf[0] = '\0'; switch (wd->sc_wdc_bio.error) { case ERR_NODEV: bp->b_flags |= B_ERROR; bp->b_error = ENXIO; break; case ERR_DMA: errbuf = "DMA error"; goto retry; case ERR_DF: errbuf = "device fault"; goto retry; case TIMEOUT: errbuf = "device timeout"; goto retry; case ERROR: /* Don't care about media change bits */ if (wd->sc_wdc_bio.r_error != 0 && (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0) goto noerror; ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf, sizeof buf); retry: /* Just reset and retry. Can we do more ? */ wdc_reset_channel(wd->drvp, 0); diskerr(bp, "wd", errbuf, LOG_PRINTF, wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label); if (wd->retries++ < WDIORETRIES) { printf(", retrying\n"); timeout_add(&wd->sc_restart_timeout, RECOVERYTIME); return; } printf("\n"); bp->b_flags |= B_ERROR; bp->b_error = EIO; break; case NOERROR: noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0) printf("%s: soft error (corrected)\n", wd->sc_dev.dv_xname); } disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid), (bp->b_flags & B_READ)); biodone(bp); wd->openings++; wdstart(wd); }
void fdcretry(struct fdc_softc *fdc) { char bits[64]; struct fd_softc *fd; struct buf *bp; fd = TAILQ_FIRST(&fdc->sc_drives); bp = BUFQ_PEEK(fd->sc_q); if (fd->sc_opts & FDOPT_NORETRY) goto fail; switch (fdc->sc_errors) { case 0: /* try again */ fdc->sc_state = DOSEEK; break; case 1: case 2: case 3: /* didn't work; try recalibrating */ fdc->sc_state = DORECAL; break; case 4: /* still no go; reset the bastard */ fdc->sc_state = DORESET; break; default: fail: if ((fd->sc_opts & FDOPT_SILENT) == 0) { diskerr(bp, "fd", "hard error", LOG_PRINTF, fd->sc_skip / FDC_BSIZE, NULL); 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]); } bp->b_error = EIO; fdfinish(fd, bp); } fdc->sc_errors++; }
void mfi_disk_complete(struct bio *bio) { struct mfi_system_pd *sc = bio->bio_driver_info; struct buf *bp = bio->bio_buf; devstat_end_transaction_buf(&sc->pd_devstat, bp); if (bio->b_flags & B_ERROR) { if (bp->b_error == 0) bp->b_error = EIO; diskerr(bio, sc->pd_disk.d_cdev, "hard error", -1, 1); kprintf("\n"); } else { bp->b_resid = 0; } biodone(bio); }
void fdretry(struct fd_softc *fd) { struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; struct buf *bp = fd->sc_bp; if (fd->sc_opts & FDOPT_NORETRY) goto fail; switch (fdc->sc_errors) { case 0: /* try again */ fdc->sc_state = DOSEEK; break; case 1: case 2: case 3: /* didn't work; try recalibrating */ fdc->sc_state = DORECAL; break; case 4: /* still no go; reset the bastard */ fdc->sc_state = DORESET; break; default: fail: diskerr(bp, "fd", "hard error", LOG_PRINTF, fd->sc_skip / FD_BSIZE(fd), (struct disklabel *)NULL); 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]); bp->b_flags |= B_ERROR; bp->b_error = EIO; bp->b_resid = bp->b_bcount; fdfinish(fd, bp); } fdc->sc_errors++; }
static void dk_done1(struct dk_softc *dksc, struct buf *bp, bool lock) { struct disk *dk = &dksc->sc_dkdev; if (bp->b_error != 0) { struct cfdriver *cd = device_cfdriver(dksc->sc_dev); diskerr(bp, cd->cd_name, "error", LOG_PRINTF, 0, dk->dk_label); printf("\n"); } if (lock) mutex_enter(&dksc->sc_iolock); disk_unbusy(dk, bp->b_bcount - bp->b_resid, (bp->b_flags & B_READ)); if (lock) mutex_exit(&dksc->sc_iolock); rnd_add_uint32(&dksc->sc_rnd_source, bp->b_rawblkno); biodone(bp); }
int mbrinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp) { struct buf *bp; u_char *cp; int dospart; struct dos_partition *dp; struct dos_partition *dp0; struct dos_partition dpcopy[NDOSPART]; int error; int max_ncyls; int max_nsectors; int max_ntracks; u_int64_t mbr_offset; char partname[2]; u_long secpercyl; char *sname = "tempname"; struct diskslice *sp; struct diskslices *ssp; cdev_t wdev; mbr_offset = DOSBBSECTOR; reread_mbr: /* * Don't bother if the block size is weird or the * media size is 0 (probably means no media present). */ if (info->d_media_blksize & DEV_BMASK) return (EIO); if (info->d_media_size == 0) return (EIO); /* * Read master boot record. */ wdev = dev; bp = geteblk((int)info->d_media_blksize); bp->b_bio1.bio_offset = (off_t)mbr_offset * info->d_media_blksize; bp->b_bio1.bio_done = biodone_sync; bp->b_bio1.bio_flags |= BIO_SYNC; bp->b_bcount = info->d_media_blksize; bp->b_cmd = BUF_CMD_READ; bp->b_flags |= B_FAILONDIS; dev_dstrategy(wdev, &bp->b_bio1); if (biowait(&bp->b_bio1, "mbrrd") != 0) { if ((info->d_dsflags & DSO_MBRQUIET) == 0) { diskerr(&bp->b_bio1, wdev, "reading primary partition table: error", LOG_PRINTF, 0); kprintf("\n"); } error = EIO; goto done; } /* Weakly verify it. */ cp = bp->b_data; sname = dsname(dev, 0, 0, 0, NULL); if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { if (bootverbose) kprintf("%s: invalid primary partition table: no magic\n", sname); error = EINVAL; goto done; } /* Make a copy of the partition table to avoid alignment problems. */ memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy)); dp0 = &dpcopy[0]; /* * Check for "Ontrack Diskmanager" or GPT. If a GPT is found in * the first dos partition, ignore the rest of the MBR and go * to GPT processing. */ for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dospart == 0 && (dp->dp_typ == DOSPTYP_PMBR || dp->dp_typ == DOSPTYP_GPT)) { if (bootverbose) kprintf( "%s: Found GPT in slice #%d\n", sname, dospart + 1); error = gptinit(dev, info, sspp); goto done; } if (dp->dp_typ == DOSPTYP_ONTRACK) { if (bootverbose) kprintf( "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname); bp->b_flags |= B_INVAL | B_AGE; brelse(bp); mbr_offset = 63; goto reread_mbr; } } if (bcmp(dp0, historical_bogus_partition_table, sizeof historical_bogus_partition_table) == 0 || bcmp(dp0, historical_bogus_partition_table_fixed, sizeof historical_bogus_partition_table_fixed) == 0) { #if 0 TRACE(("%s: invalid primary partition table: historical\n", sname)); #endif /* 0 */ if (bootverbose) kprintf( "%s: invalid primary partition table: Dangerously Dedicated (ignored)\n", sname); error = EINVAL; goto done; } /* Guess the geometry. */ /* * TODO: * Perhaps skip entries with 0 size. * Perhaps only look at entries of type DOSPTYP_386BSD. */ max_ncyls = 0; max_nsectors = 0; max_ntracks = 0; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { int ncyls; int nsectors; int ntracks; ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1; if (max_ncyls < ncyls) max_ncyls = ncyls; nsectors = DPSECT(dp->dp_esect); if (max_nsectors < nsectors) max_nsectors = nsectors; ntracks = dp->dp_ehd + 1; if (max_ntracks < ntracks) max_ntracks = ntracks; } /* * Check that we have guessed the geometry right by checking the * partition entries. */ /* * TODO: * As above. * Check for overlaps. * Check against d_secperunit if the latter is reliable. */ error = 0; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 && dp->dp_start == 0 && dp->dp_size == 0) continue; //sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart, // WHOLE_SLICE_PART, partname); /* * Temporarily ignore errors from this check. We could * simplify things by accepting the table eariler if we * always ignore errors here. Perhaps we should always * accept the table if the magic is right but not let * bad entries affect the geometry. */ check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks, mbr_offset); } if (error != 0) goto done; /* * Accept the DOS partition table. * * Adjust the disk information structure with updated CHS * conversion parameters, but only use values extracted from * the primary partition table. * * NOTE! Regardless of our having to deal with this old cruft, * we do not screw around with the info->d_media* parameters. */ secpercyl = (u_long)max_nsectors * max_ntracks; if (secpercyl != 0 && mbr_offset == DOSBBSECTOR) { info->d_secpertrack = max_nsectors; info->d_nheads = max_ntracks; info->d_secpercyl = secpercyl; info->d_ncylinders = info->d_media_blocks / secpercyl; } /* * We are passed a pointer to a suitably initialized minimal * slices "struct" with no dangling pointers in it. Replace it * by a maximal one. This usually oversizes the "struct", but * enlarging it while searching for logical drives would be * inconvenient. */ kfree(*sspp, M_DEVBUF); ssp = dsmakeslicestruct(MAX_SLICES, info); *sspp = ssp; /* Initialize normal slices. */ sp = &ssp->dss_slices[BASE_SLICE]; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) { sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart, WHOLE_SLICE_PART, partname); (void)mbr_setslice(sname, info, sp, dp, mbr_offset); } ssp->dss_nslices = BASE_SLICE + NDOSPART; /* Handle extended partitions. */ sp -= NDOSPART; for (dospart = 0; dospart < NDOSPART; dospart++, sp++) { if (sp->ds_type == DOSPTYP_EXTENDED || sp->ds_type == DOSPTYP_EXTENDEDX) { mbr_extended(wdev, info, ssp, sp->ds_offset, sp->ds_size, sp->ds_offset, max_nsectors, max_ntracks, mbr_offset, 1); } } /* * mbr_extended() abuses ssp->dss_nslices for the number of slices * that would be found if there were no limit on the number of slices * in *ssp. Cut it back now. */ if (ssp->dss_nslices > MAX_SLICES) ssp->dss_nslices = MAX_SLICES; done: bp->b_flags |= B_INVAL | B_AGE; brelse(bp); if (error == EINVAL) error = 0; return (error); }
static void mbr_extended(cdev_t dev, struct disk_info *info, struct diskslices *ssp, u_int64_t ext_offset, u_int64_t ext_size, u_int64_t base_ext_offset, int nsectors, int ntracks, u_int64_t mbr_offset, int level) { struct buf *bp; u_char *cp; int dospart; struct dos_partition *dp; struct dos_partition dpcopy[NDOSPART]; u_int64_t ext_offsets[NDOSPART]; u_int64_t ext_sizes[NDOSPART]; char partname[2]; int slice; char *sname; struct diskslice *sp; if (level >= 16) { kprintf( "%s: excessive recursion in search for slices; aborting search\n", devtoname(dev)); return; } /* Read extended boot record. */ bp = geteblk((int)info->d_media_blksize); bp->b_bio1.bio_offset = (off_t)ext_offset * info->d_media_blksize; bp->b_bio1.bio_done = biodone_sync; bp->b_bio1.bio_flags |= BIO_SYNC; bp->b_bcount = info->d_media_blksize; bp->b_cmd = BUF_CMD_READ; bp->b_flags |= B_FAILONDIS; dev_dstrategy(dev, &bp->b_bio1); if (biowait(&bp->b_bio1, "mbrrd") != 0) { diskerr(&bp->b_bio1, dev, "reading extended partition table: error", LOG_PRINTF, 0); kprintf("\n"); goto done; } /* Weakly verify it. */ cp = bp->b_data; if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE, WHOLE_SLICE_PART, partname); if (bootverbose) kprintf("%s: invalid extended partition table: no magic\n", sname); goto done; } /* Make a copy of the partition table to avoid alignment problems. */ memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy)); slice = ssp->dss_nslices; for (dospart = 0, dp = &dpcopy[0]; dospart < NDOSPART; dospart++, dp++) { ext_sizes[dospart] = 0; if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 && dp->dp_start == 0 && dp->dp_size == 0) continue; if (dp->dp_typ == DOSPTYP_EXTENDED || dp->dp_typ == DOSPTYP_EXTENDEDX) { static char buf[32]; sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE, WHOLE_SLICE_PART, partname); ksnprintf(buf, sizeof(buf), "%s", sname); if (strlen(buf) < sizeof buf - 11) strcat(buf, "<extended>"); check_part(buf, dp, base_ext_offset, nsectors, ntracks, mbr_offset); ext_offsets[dospart] = base_ext_offset + dp->dp_start; ext_sizes[dospart] = dp->dp_size; } else { sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); check_part(sname, dp, ext_offset, nsectors, ntracks, mbr_offset); if (slice >= MAX_SLICES) { kprintf("%s: too many slices\n", sname); slice++; continue; } sp = &ssp->dss_slices[slice]; if (mbr_setslice(sname, info, sp, dp, ext_offset) != 0) continue; slice++; } } ssp->dss_nslices = slice; /* If we found any more slices, recursively find all the subslices. */ for (dospart = 0; dospart < NDOSPART; dospart++) { if (ext_sizes[dospart] != 0) { mbr_extended(dev, info, ssp, ext_offsets[dospart], ext_sizes[dospart], base_ext_offset, nsectors, ntracks, mbr_offset, ++level); } } done: bp->b_flags |= B_INVAL | B_AGE; brelse(bp); }
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 }