📄 wd.c
字号:
biodone(bp); if (wd != NULL) device_unref(&wd->sc_dev);}/* * Queue a drive for I/O. */voidwdstart(arg) void *arg;{ struct wd_softc *wd = arg; struct buf *dp, *bp=0; WDCDEBUG_PRINT(("wdstart %s\n", wd->sc_dev.dv_xname), DEBUG_XFERS); while (wd->openings > 0) { /* Is there a buf for us ? */ dp = &wd->sc_q; if ((bp = dp->b_actf) == NULL) /* yes, an assign */ return; dp->b_actf = bp->b_actf; /* * Make the command. First lock the device */ wd->openings--; wd->retries = 0; __wdstart(wd, bp); }}void__wdstart(wd, bp) struct wd_softc *wd; struct buf *bp;{ daddr_t p_offset; if (WDPART(bp->b_dev) != RAW_PART) p_offset = wd->sc_dk.dk_label->d_partitions[WDPART(bp->b_dev)].p_offset; else p_offset = 0; wd->sc_wdc_bio.lp=wd->sc_dk.dk_label; wd->sc_wdc_bio.blkno = bp->b_blkno + p_offset; wd->sc_wdc_bio.blkno /= (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); wd->sc_wdc_bio.blkdone =0; wd->sc_bp = bp; /* * If we're retrying, retry in single-sector mode. This will give us * the sector number of the problem, and will eventually allow the * transfer to succeed. */ if (wd->sc_multi == 1 || wd->retries >= WDIORETRIES_SINGLE) wd->sc_wdc_bio.flags = ATA_SINGLE | ATA_POLL; else wd->sc_wdc_bio.flags = ATA_POLL; if (wd->sc_flags & WDF_LBA) wd->sc_wdc_bio.flags |= ATA_LBA; if (bp->b_flags & B_READ) wd->sc_wdc_bio.flags |= ATA_READ; wd->sc_wdc_bio.bcount = bp->b_bcount; wd->sc_wdc_bio.databuf = bp->b_data; wd->sc_wdc_bio.wd = wd;#ifndef PMON /* Instrumentation. */ disk_busy(&wd->sc_dk);#endif switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { case WDC_TRY_AGAIN: timeout(wdrestart, wd, hz); break; case WDC_QUEUED: break; case WDC_COMPLETE: wddone(wd); break; default: panic("__wdstart: bad return code from wdc_ata_bio()"); }}voidwddone(v) 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);retry: /* Just reset and retry. Can we do more ? */ wdc_reset_channel(wd->drvp);#ifndef PMON diskerr(bp, "wd", errbuf, LOG_PRINTF, wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);#endif if (wd->retries++ < WDIORETRIES) { printf(", retrying\n"); timeout(wdrestart, wd, 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); }#ifndef PMON disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));#if NRND > 0 rnd_add_uint32(&wd->rnd_source, bp->b_blkno);#endif#endif biodone(bp); wd->openings++; wdstart(wd);}voidwdrestart(v) void *v;{ struct wd_softc *wd = v; struct buf *bp = wd->sc_bp; int s; WDCDEBUG_PRINT(("wdrestart %s\n", wd->sc_dev.dv_xname), DEBUG_XFERS); s = splbio(); __wdstart(v, bp); splx(s);}intwdread(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ WDCDEBUG_PRINT(("wdread\n"), DEBUG_XFERS); return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));}intwdwrite(dev, uio, flags) dev_t dev; struct uio *uio; int flags;{ WDCDEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS); return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));}intwdopen(dev, flag, fmt, p) dev_t dev; int flag, fmt; struct proc *p;{ struct wd_softc *wd; int unit, part; int error; WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); unit = WDUNIT(dev); wd = wdlookup(unit); if (wd == NULL) return ENXIO; /* * If this is the first open of this device, add a reference * to the adapter. */#ifndef __OpenBSD__ if (wd->sc_dk.dk_openmask == 0 && (error = wdc_ata_addref(wd->drvp)) != 0) return (error);#endif if ((error = wdlock(wd)) != 0) goto bad4; if (wd->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto bad3; } } else { if ((wd->sc_flags & WDF_LOADED) == 0) { wd->sc_flags |= WDF_LOADED; wd_get_params(wd, AT_WAIT, &wd->sc_params); /* Load the physical device parameters. */ if(wd->sc_dk.dk_cpulabel==NULL) wd->sc_dk.dk_cpulabel=(struct cpu_disklabel *)malloc(sizeof(struct cpu_disklabel),M_DEVBUF,M_NOWAIT); if(wd->sc_dk.dk_label==NULL) wd->sc_dk.dk_label=(struct disklabel *)malloc(sizeof(struct disklabel),M_DEVBUF,M_NOWAIT); /* Load the partition info if not already loaded. */ wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel, 0); } } part = WDPART(dev); /* Check that the partition exists. */ if (part != RAW_PART && (part >= wd->sc_dk.dk_label->d_npartitions || wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { error = ENXIO; goto bad; } /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: wd->sc_dk.dk_copenmask |= (1 << part); break; case S_IFBLK: wd->sc_dk.dk_bopenmask |= (1 << part); break; } wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; wdunlock(wd); device_unref(&wd->sc_dev); return 0;bad: if (wd->sc_dk.dk_openmask == 0) { }bad3: wdunlock(wd);bad4:#ifndef __OpenBSD__ if (wd->sc_dk.dk_openmask == 0) wdc_ata_delref(wd->drvp);#endif device_unref(&wd->sc_dev); return error;}intwdclose(dev, flag, fmt, p) dev_t dev; int flag, fmt; struct proc *p;{ struct wd_softc *wd; int part = WDPART(dev); int error = 0; wd = wdlookup(WDUNIT(dev)); if (wd == NULL) return ENXIO; WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS); if ((error = wdlock(wd)) != 0) goto exit; switch (fmt) { case S_IFCHR: wd->sc_dk.dk_copenmask &= ~(1 << part); break; case S_IFBLK: wd->sc_dk.dk_bopenmask &= ~(1 << part); break; } wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; if (wd->sc_dk.dk_openmask == 0) { wd_flushcache(wd,0); /* XXXX Must wait for I/O to complete! */#ifndef __OpenBSD__ wdc_ata_delref(wd->drvp);#endif } wdunlock(wd); exit: device_unref(&wd->sc_dev); return (error);}voidwdgetdefaultlabel(wd, lp) struct wd_softc *wd; struct disklabel *lp;{ WDCDEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS); bzero(lp, sizeof(struct disklabel)); lp->d_secsize = DEV_BSIZE; lp->d_ntracks = wd->sc_params.atap_heads; lp->d_nsectors = wd->sc_params.atap_sectors; lp->d_ncylinders = wd->sc_params.atap_cylinders; lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; if (wd->drvp->ata_vers == -1) { lp->d_type = DTYPE_ST506; strncpy(lp->d_typename, "ST506/MFM/RLL", 16); } else { lp->d_type = DTYPE_ESDI; strncpy(lp->d_typename, "ESDI/IDE disk", 16); } /* XXX - user viscopy() like sd.c */ strncpy(lp->d_packname, wd->sc_params.atap_model, 16); lp->d_secperunit = wd->sc_capacity; lp->d_rpm = 3600; lp->d_interleave = 1; lp->d_flags = 0; lp->d_partitions[RAW_PART].p_offset = 0; lp->d_partitions[RAW_PART].p_size = lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; lp->d_npartitions = RAW_PART + 1; lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC;#ifndef PMON lp->d_checksum = dkcksum(lp);#endif}/* * Fabricate a default disk label, and try to read the correct one. */voidwdgetdisklabel(dev, wd, lp, clp, spoofonly) dev_t dev; struct wd_softc *wd; struct disklabel *lp; struct cpu_disklabel *clp; int spoofonly;{ char *errstring; WDCDEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS); bzero(clp, sizeof(struct cpu_disklabel)); wdgetdefaultlabel(wd, lp); wd->sc_badsect[0] = -1; if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET; errstring = readdisklabel(WDLABELDEV(dev), wdstrategy, lp, clp, spoofonly); if (errstring) { /* * This probably happened because the drive's default * geometry doesn't match the DOS geometry. We * assume the DOS geometry is now in the label and try * again. XXX This is a kluge. */ if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET; errstring = readdisklabel(WDLABELDEV(dev), wdstrategy, lp, clp, spoofonly); }#ifndef PMON if (errstring) { printf("%s: %s\n", wd->sc_dev.dv_xname, errstring); return; }#endif if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET;#ifdef DKBAD if ((lp->d_flags & D_BADSECT) != 0) bad144intern(wd);#endif}intwdioctl(dev, xfer, addr, flag, p) dev_t dev; u_long xfer; caddr_t addr; int flag; struct proc *p;{ struct wd_softc *wd; int error = 0; WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); wd = wdlookup(WDUNIT(dev)); if (wd == NULL) return ENXIO; if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto exit; } switch (xfer) {#ifndef PMON#ifdef DKBAD case DIOCSBAD: if ((flag & FWRITE) == 0) return EBADF; DKBAD(wd->sc_dk.dk_cpulabel) = *(struct dkbad *)addr; wd->sc_dk.dk_label->d_flags |= D_BADSECT; bad144intern(wd); goto exit;#endif case DIOCRLDINFO: wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel, 0); goto exit; case DIOCGPDINFO: { struct cpu_disklabel osdep; wdgetdisklabel(dev, wd, (struct disklabel *)addr, &osdep, 1); goto exit; } case DIOCGDINFO: *(struct disklabel *)addr = *(wd->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &wd->sc_dk.dk_label->d_partitions[WDPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = wdlock(wd)) != 0) goto exit; wd->sc_flags |= WDF_LABELLING; error = setdisklabel(wd->sc_dk.dk_label, (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0, wd->sc_dk.dk_cpulabel); if (error == 0) { if (wd->drvp->state > RECAL) wd->drvp->drive_flags |= DRIVE_RESET; if (xfer == DIOCWDINFO) error = writedisklabel(WDLABELDEV(dev), wdstrategy, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel); } wd->sc_flags &= ~WDF_LABELLING; wdunlock(wd); goto exit; case DIOCWLABEL: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if (*(int *)addr) wd->sc_flags |= WDF_WLABEL; else wd->sc_flags &= ~WDF_WLABEL; goto exit;#ifndef __OpenBSD__ case DIOCGDEFLABEL: wdgetdefaultlabel(wd, (struct disklabel *)addr); goto exit;#endif#ifdef notyet case DIOCWFORMAT: if ((flag & FWRITE) == 0) return EBADF; { register struct format_op *fop; struct iovec aiov; struct uio auio; fop = (struct format_op *)addr; aiov.iov_base = fop->df_buf; aiov.iov_len = fop->df_count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * wd->sc_dk.dk_label->d_secsize; auio.uio_procp = p; error = physio(wdformat, NULL, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = wdc->sc_status; fop->df_reg[1] = wdc->sc_error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -