📄 vd.c
字号:
bp->b_error = ENXIO; goto bad; } vi = vddinfo[unit]; lp = &dklabel[unit]; if (vi == 0 || vi->ui_alive == 0) { bp->b_error = ENXIO; goto bad; } dk = &dksoftc[unit]; if (dk->dk_state < OPEN) { if (dk->dk_state == CLOSED) { bp->b_error = EIO; goto bad; } goto q; } if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; goto bad; } part = vdpart(bp->b_dev); if ((dk->dk_openpart & (1 << part)) == 0) { bp->b_error = ENODEV; goto bad; } sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; maxsz = lp->d_partitions[part].p_size;#ifndef SECSIZE sn = bp->b_blkno << dk->dk_bshift;#else SECSIZE sn = bp->b_blkno;#endif SECSIZE if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&#if LABELSECTOR != 0 sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&#endif (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { bp->b_error = EROFS; goto bad; } if (sn < 0 || sn + sz > maxsz) { if (sn == maxsz) { bp->b_resid = bp->b_bcount; goto done; } sz = maxsz - sn; if (sz <= 0) { bp->b_error = EINVAL; goto bad; } bp->b_bcount = sz * lp->d_secsize; } bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;#ifdef SECSIZEif (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)panic("vdstrat blksize");#endif SECSIZEq: s = spl7(); dp = &dkutab[vi->ui_unit]; disksort(dp, bp); if (!dp->b_active) { (void) vdustart(vi); if (!vi->ui_mi->um_tab.b_active) vdstart(vi->ui_mi); } splx(s); return;bad: bp->b_flags |= B_ERROR;done: biodone(bp); return;}vdustart(vi) register struct vba_device *vi;{ register struct buf *bp, *dp; register struct vba_ctlr *vm; register int unit = vi->ui_unit; register struct dksoftc *dk; register struct vdsoftc *vd; struct disklabel *lp; dp = &dkutab[unit]; /* * If queue empty, nothing to do. */ if ((bp = dp->b_actf) == NULL) return; /* * If drive is off-cylinder and controller supports seeks, * place drive on seek queue for controller. * Otherwise, place on transfer queue. */ vd = &vdsoftc[vi->ui_ctlr]; dk = &dksoftc[unit]; vm = vi->ui_mi; if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { lp = &dklabel[unit]; bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; if (vm->um_tab.b_seekf == NULL) vm->um_tab.b_seekf = dp; else vm->um_tab.b_seekl->b_forw = dp; vm->um_tab.b_seekl = dp; } else { if (vm->um_tab.b_actf == NULL) vm->um_tab.b_actf = dp; else vm->um_tab.b_actl->b_forw = dp; vm->um_tab.b_actl = dp; } dp->b_forw = NULL; dp->b_active++;}/* * Start next transfer on a controller. * There are two queues of drives, the first on-cylinder * and the second off-cylinder from their next transfers. * Perform the first transfer for the first drive on the on-cylinder * queue, if any, otherwise the first transfer for the first drive * on the second queue. Initiate seeks on remaining drives on the * off-cylinder queue, then move them all to the on-cylinder queue. */vdstart(vm) register struct vba_ctlr *vm;{ register struct buf *bp; register struct vba_device *vi; register struct vdsoftc *vd; register struct dksoftc *dk; register struct disklabel *lp; register struct dcb **dcbp; struct buf *dp; int sn, tn;loop: /* * Pull a request off the controller queue. */ if ((dp = vm->um_tab.b_actf) == NULL && (dp = vm->um_tab.b_seekf) == NULL) return; if ((bp = dp->b_actf) == NULL) { if (dp == vm->um_tab.b_actf) vm->um_tab.b_actf = dp->b_forw; else vm->um_tab.b_seekf = dp->b_forw; goto loop; } /* * Mark controller busy, and determine * destination of this request. */ vm->um_tab.b_active++; vi = vddinfo[vdunit(bp->b_dev)]; dk = &dksoftc[vi->ui_unit];#ifndef SECSIZE sn = bp->b_blkno << dk->dk_bshift;#else SECSIZE sn = bp->b_blkno;#endif SECSIZE lp = &dklabel[vi->ui_unit]; sn %= lp->d_secpercyl; tn = sn / lp->d_nsectors; sn %= lp->d_nsectors; /* * Construct dcb for read/write command. */ vd = &vdsoftc[vm->um_ctlr]; vd->vd_dcb.intflg = DCBINT_DONE; vd->vd_dcb.devselect = dk->dk_dcb.devselect; vd->vd_dcb.operrsta = 0; vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; vd->vd_dcb.trail.rwtrail.disk.track = tn; vd->vd_dcb.trail.rwtrail.disk.sector = sn; dk->dk_curcyl = bp->b_cylin; bp->b_track = 0; /* init overloaded field */ vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); if (bp->b_flags & B_FORMAT) vd->vd_dcb.opcode = dk->dk_op; else if (vd->vd_flags & VD_SCATGATH && ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; else vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; switch (vd->vd_dcb.opcode) { case VDOP_FSECT: vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long); vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / lp->d_secsize; vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; goto setupaddr; case VDOP_RDRAW: case VDOP_RD: case VDOP_RHDE: case VDOP_WD: vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;setupaddr: vd->vd_dcb.trail.rwtrail.memadr = vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); break; case VDOP_RAS: case VDOP_GAW: vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf, &vd->vd_dcb.trail.sgtrail); break; } if (vi->ui_dk >= 0) { dk_busy |= 1<<vi->ui_dk; dk_xfer[vi->ui_dk]++; dk_wds[vi->ui_dk] += bp->b_bcount>>6; } /* * Look for any seeks to be performed on other drives on this * controller. If overlapped seeks exist, insert seek commands * on the controller's command queue before the transfer. */ dcbp = &vd->vd_mdcb.mdcb_head; if (dp == vm->um_tab.b_seekf) dp = dp->b_forw; else dp = vm->um_tab.b_seekf; for (; dp != NULL; dp = dp->b_forw) { if ((bp = dp->b_actf) == NULL) continue; vi = vddinfo[vdunit(bp->b_dev)]; dk = &dksoftc[vi->ui_unit]; dk->dk_curcyl = bp->b_cylin; if (vi->ui_dk >= 0) dk_seek[vi->ui_dk]++; dk->dk_dcb.operrsta = 0; dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; *dcbp = (struct dcb *)dk->dk_dcbphys; dcbp = &dk->dk_dcb.nxtdcb; } *dcbp = (struct dcb *)vd->vd_dcbphys; if (vm->um_tab.b_actf) vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; else vm->um_tab.b_actf = vm->um_tab.b_seekf; if (vm->um_tab.b_seekf) vm->um_tab.b_actl = vm->um_tab.b_seekl; vm->um_tab.b_seekf = 0; /* * Initiate operation. */ vd->vd_mdcb.mdcb_status = 0; VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);}/* * Wait for controller to finish current operation * so that direct controller accesses can be done. */vdlock(ctlr){ register struct vba_ctlr *vm = vdminfo[ctlr]; register struct vdsoftc *vd = &vdsoftc[ctlr]; int s; s = spl7(); while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { vd->vd_flags |= VD_WAIT; sleep((caddr_t)vd, PRIBIO); } vd->vd_flags |= VD_LOCKED; splx(s);}/* * Continue normal operations after pausing for * munging the controller directly. */vdunlock(ctlr){ register struct vba_ctlr *vm = vdminfo[ctlr]; register struct vdsoftc *vd = &vdsoftc[ctlr]; vd->vd_flags &= ~VD_LOCKED; if (vd->vd_flags & VD_WAIT) { vd->vd_flags &= ~VD_WAIT; wakeup((caddr_t)vd); } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) vdstart(vm);}#define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)/* * Handle a disk interrupt. */vdintr(ctlr) register ctlr;{ register struct buf *bp, *dp; register struct vba_ctlr *vm = vdminfo[ctlr]; register struct vba_device *vi; register struct vdsoftc *vd = &vdsoftc[ctlr]; register status; int timedout; struct dksoftc *dk; if (!vm->um_tab.b_active) { printf("vd%d: stray interrupt\n", ctlr); return; } /* * Get device and block structures, and a pointer * to the vba_device for the drive. */ dp = vm->um_tab.b_actf; bp = dp->b_actf; vi = vddinfo[vdunit(bp->b_dev)]; dk = &dksoftc[vi->ui_unit]; if (vi->ui_dk >= 0) dk_busy &= ~(1<<vi->ui_dk); timedout = (vd->vd_wticks >= VDMAXTIME); /* * Check for and process errors on * either the drive or the controller. */ uncache(&vd->vd_dcb.operrsta); status = vd->vd_dcb.operrsta; if (bp->b_flags & B_FORMAT) { dk->dk_operrsta = status; uncache(&vd->vd_dcb.err_code); /* ecodecnt gets err_code + err_wcnt from the same longword */ dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code; uncache(&vd->vd_dcb.err_trk); /* erraddr gets error trk/sec/cyl from the same longword */ dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk; } else if (status & VDERR_HARD || timedout) { if (vd->vd_type == VDTYPE_SMDE) uncache(&vd->vd_dcb.err_code); if (status & DCBS_WPT) { /* * Give up on write locked devices immediately. */ printf("dk%d: write locked\n", vi->ui_unit); bp->b_flags |= B_ERROR; } else if (status & VDERR_RETRY || timedout) { if (status & VDERR_CTLR || timedout) { vdharderr(timedout ? "controller timeout" : "controller err", vd, bp, &vd->vd_dcb); printf("; resetting controller..."); vdreset_ctlr(vm); } else if (status & VDERR_DRIVE) { vdharderr("drive err", vd, bp, &vd->vd_dcb); printf("; resetting drive..."); if (!vdreset_drive(vi)) dk->dk_state = CLOSED; } else vdharderr("data err", vd, bp, &vd->vd_dcb); /* * Retry transfer once, unless reset failed. */ if (!vi->ui_alive || dp->b_errcnt++ >= 1) { printf("\n"); goto hard; } printf(" retrying\n"); vm->um_tab.b_active = 0; /* force retry */ } else { vdharderr("hard error", vd, bp, &vd->vd_dcb); printf("\n"); hard: bp->b_flags |= B_ERROR; } } else if (status & DCBS_SOFT) vdsofterr(bp, &vd->vd_dcb);if (vd->vd_wticks > 3) {vd->vd_dcb.err_code = vd->vd_wticks;vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);printf("\n");} vd->vd_wticks = 0; if (vm->um_tab.b_active) { vm->um_tab.b_active = 0; vm->um_tab.b_actf = dp->b_forw; dp->b_active = 0; dp->b_errcnt = 0; dp->b_actf = bp->av_forw; bp->b_resid = 0; vbadone(bp, &vd->vd_rbuf); biodone(bp); /* * If this unit has more work to do, * then start it up right away. */ if (dp->b_actf) vdustart(vi); else if (dk->dk_openpart == 0) wakeup((caddr_t)dk); } /* * If there are devices ready to * transfer, start the controller. */ if (vd->vd_flags & VD_WAIT) { vd->vd_flags &= ~VD_WAIT; wakeup((caddr_t)vd); } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) vdstart(vm);}vdharderr(what, vd, bp, dcb) char *what; struct vdsoftc *vd; register struct buf *bp; register struct dcb *dcb;{ int unit = vdunit(bp->b_dev), status = dcb->operrsta; register struct disklabel *lp = &dklabel[unit]; int blkdone; if (vd->vd_wticks < VDMAXTIME) status &= ~DONTCARE; blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * lp->d_nsectors + dcb->err_sec - lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> dksoftc[unit].dk_bshift) - bp->b_blkno; diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); printf(", status %b", status, VDERRBITS); if (vd->vd_type == VDTYPE_SMDE) printf(" ecode %x", dcb->err_code);}vdsofterr(bp, dcb) register struct buf *bp; register struct dcb *dcb;{ int unit = vdunit(bp->b_dev); struct disklabel *lp = &dklabel[unit]; int status = dcb->operrsta; int blkdone; blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * lp->d_nsectors + dcb->err_sec - lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> dksoftc[unit].dk_bshift) - bp->b_blkno; if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); addlog(", status %b ecode %x\n", status, VDERRBITS, dcb->err_code); } else { diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); addlog("\n"); }}vdioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ register int unit = vdunit(dev); register struct disklabel *lp = &dklabel[unit]; register struct dksoftc *dk = &dksoftc[unit]; int error = 0, vdformat(); switch (cmd) { case DIOCGDINFO: *(struct disklabel *)data = *lp; break; case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[vdpart(dev)]; break; case DIOCSDINFO: if ((flag & FWRITE) == 0) error = EBADF; else error = setdisklabel(lp, (struct disklabel *)data, (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); if (error == 0 && dk->dk_state == OPENRAW && vdreset_drive(vddinfo[unit])) dk->dk_state = OPEN; break; case DIOCWLABEL: if ((flag & FWRITE) == 0) error = EBADF; else dk->dk_wlabel = *(int *)data; break; case DIOCWDINFO: if ((flag & FWRITE) == 0) error = EBADF; else if ((error = setdisklabel(lp, (struct disklabel *)data, (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { int wlab; if (error == 0 && dk->dk_state == OPENRAW && vdreset_drive(vddinfo[unit])) dk->dk_state = OPEN; /* simulate opening partition 0 so write succeeds */ dk->dk_openpart |= (1 << 0); /* XXX */ wlab = dk->dk_wlabel; dk->dk_wlabel = 1; error = writedisklabel(dev, vdstrategy, lp); dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; dk->dk_wlabel = wlab; } break; case DIOCWFORMAT: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -