📄 hd.c
字号:
register int unit; daddr_t sn, sz, maxsz; int part, s; vi = hddinfo[unit = hdunit(bp->b_dev)]; if (unit >= NHD || vi == 0 || vi->ui_alive == 0) { bp->b_error = ENXIO; goto bad; } dk = &dksoftc[unit]; if (dk->dk_state < OPEN) goto q; if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; goto bad; } part = hdpart(bp->b_dev); if ((dk->dk_openpart & (1 << part)) == 0) { bp->b_error = ENODEV; goto bad; } lp = &dk->dk_label; sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; maxsz = lp->d_partitions[part].p_size; sn = bp->b_blkno << dk->dk_bshift; 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;q: s = spl7(); dp = &dk->dk_utab; disksort(dp, bp); if (!dp->b_active) { (void)hdustart(vi); if (!vi->ui_mi->um_tab.b_active) hdcstart(vi->ui_mi); } splx(s); return;bad: bp->b_flags |= B_ERROR;done: biodone(bp);}hdustart(vi) register struct vba_device *vi;{ register struct buf *bp, *dp; register struct vba_ctlr *vm; register struct dksoftc *dk; dk = &dksoftc[vi->ui_unit]; dp = &dk->dk_utab; /* if queue empty, nothing to do. impossible? */ if (dp->b_actf == NULL) return; /* place on controller transfer queue */ vm = vi->ui_mi; 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++;}hdcstart(vm) register struct vba_ctlr *vm;{ register struct buf *bp; register struct dksoftc *dk; register struct disklabel *lp; register struct master_mcb *master; register struct mcb *mcb; struct vba_device *vi; struct hdcsoftc *hdc; struct buf *dp; int sn; /* pull a request off the controller queue */ for (;;) { if ((dp = vm->um_tab.b_actf) == NULL) return; if (bp = dp->b_actf) break; vm->um_tab.b_actf = dp->b_forw; } /* mark controller active */ vm->um_tab.b_active++; vi = hddinfo[hdunit(bp->b_dev)]; dk = &dksoftc[vi->ui_unit]; lp = &dk->dk_label; sn = bp->b_blkno << dk->dk_bshift; /* fill in mcb */ mcb = &dk->dk_mcb; mcb->forw_phaddr = 0; /* mcb->priority = 0; */ mcb->interrupt = 1; mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE; mcb->cyl = bp->b_cylin;/* assumes partition starts on cylinder boundary */ mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks; mcb->sector = sn % lp->d_nsectors; mcb->drive = vi->ui_slave; /* mcb->context = 0; /* what do we want on interrupt? */ hdc = &hdcsoftc[vm->um_ctlr]; if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) { mcb->chain[0].wcount = (bp->b_bcount+3) >> 2; mcb->chain[0].memadr = vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize); } 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; } master = &hdc->hdc_mcb; master->mcw = MCL_QUEUED; master->interrupt = HDCINTERRUPT + vm->um_ctlr; master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;}/* * Wait for controller to finish current operation * so that direct controller accesses can be done. */hdclock(ctlr) int ctlr;{ register struct vba_ctlr *vm = hdcminfo[ctlr]; register struct hdcsoftc *hdc; int s; hdc = &hdcsoftc[ctlr]; s = spl7(); while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) { hdc->hdc_flags |= HDC_WAIT; sleep((caddr_t)hdc, PRIBIO); } hdc->hdc_flags |= HDC_LOCKED; splx(s);}/* * Continue normal operations after pausing for * munging the controller directly. */hdcunlock(ctlr) int ctlr;{ register struct vba_ctlr *vm; register struct hdcsoftc *hdc = &hdcsoftc[ctlr]; hdc->hdc_flags &= ~HDC_LOCKED; if (hdc->hdc_flags & HDC_WAIT) { hdc->hdc_flags &= ~HDC_WAIT; wakeup((caddr_t)hdc); } else { vm = hdcminfo[ctlr]; if (vm->um_tab.b_actf) hdcstart(vm); }}hdintr(ctlr) int ctlr;{ register struct buf *bp, *dp; register struct vba_ctlr *vm; register struct vba_device *vi; register struct hdcsoftc *hdc; register struct mcb *mcb; struct master_mcb *master; register int status; int timedout; struct dksoftc *dk; hdc = &hdcsoftc[ctlr]; master = &hdc->hdc_mcb; uncache(&master->mcs); uncache(&master->context); vm = hdcminfo[ctlr]; if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) { printf("hd%d: stray interrupt\n", ctlr); return; } dp = vm->um_tab.b_actf; bp = dp->b_actf; vi = hddinfo[hdunit(bp->b_dev)]; dk = &dksoftc[vi->ui_unit]; if (vi->ui_dk >= 0) dk_busy &= ~(1<<vi->ui_dk); timedout = (hdc->hdc_wticks >= HDCMAXTIME); mcb = &dk->dk_mcb; if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout) hdcerror(ctlr, *(u_long *)master->xstatus); else hdc->hdc_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, &hdc->hdc_rbuf); biodone(bp); /* start up now, if more work to do */ if (dp->b_actf) hdustart(vi); else if (dk->dk_openpart == 0) wakeup((caddr_t)dk); } /* if there are devices ready to transfer, start the controller. */ if (hdc->hdc_flags & HDC_WAIT) { hdc->hdc_flags &= ~HDC_WAIT; wakeup((caddr_t)hdc); } else if (vm->um_tab.b_actf) hdcstart(vm);}hdioctl(dev, cmd, data, flag) dev_t dev; int cmd, flag; caddr_t data;{ register int unit; register struct dksoftc *dk; register struct disklabel *lp; int error; unit = hdunit(dev); dk = &dksoftc[unit]; lp = &dk->dk_label; error = 0; switch (cmd) { case DIOCGDINFO: *(struct disklabel *)data = *lp; break; case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[hdpart(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) 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) 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, hdstrategy, lp); dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; dk->dk_wlabel = wlab; } break; default: error = ENOTTY; break; } return (error);}/* * Watch for lost interrupts. */hdcwatch(){ register struct hdcsoftc *hdc; register struct vba_ctlr **vmp; register int ctlr; int s; timeout(hdcwatch, (caddr_t)0, hz); for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC; ++ctlr, ++vmp, ++hdc) { if (*vmp == 0 || (*vmp)->um_alive == 0) continue; s = spl7(); if ((*vmp)->um_tab.b_active && hdc->hdc_wticks++ >= HDCMAXTIME) { printf("hd%d: lost interrupt\n", ctlr); hdintr(ctlr); } splx(s); }}hddump(dev) dev_t dev;{ return(ENXIO);}hdsize(dev) dev_t dev;{ register int unit = hdunit(dev); register struct dksoftc *dk; struct vba_device *vi; struct disklabel *lp; if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 || (dk = &dksoftc[unit])->dk_state != OPEN) return (-1); lp = &dk->dk_label; return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift);}hdimcb(dk) register struct dksoftc *dk;{ register struct master_mcb *master; register struct mcb *mcb; register struct hdcsoftc *hdc; int timeout; /* fill in mcb */ mcb = &dk->dk_mcb; mcb->interrupt = 0; mcb->forw_phaddr = 0; mcb->drive = dk->dk_unit; hdc = &hdcsoftc[dk->dk_ctlr]; master = &hdc->hdc_mcb; /* fill in master mcb */ master->mcw = MCL_IMMEDIATE; master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); master->mcs = 0; /* kick controller and wait */ hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp; for (timeout = 15000; timeout; --timeout) { DELAY(1000); mtpr(PADC, 0); if (master->mcs&MCS_FATALERROR) { printf("hdc%d: fatal error\n", dk->dk_ctlr); hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus); return(1); } if (master->mcs&MCS_DONE) return(0); } printf("hdc%d: timed out\n", dk->dk_ctlr); return(1);}hdcerror(ctlr, code) int ctlr; u_long code;{ printf("hd%d: error %lx\n", ctlr, code);}#ifdef COMPAT_42hdreadgeometry(dk) struct dksoftc *dk;{ static geometry_sector geometry; register struct mcb *mcb; register struct disklabel *lp; geometry_block *geo; int cnt; /* * Read the geometry block (at head = 0 sector = 0 of the drive * definition cylinder), validate it (must have the correct version * number, header, and checksum). */ mcb = &dk->dk_mcb; mcb->command = HCMD_READ; mcb->cyl = dk->dk_def_cyl; mcb->head = 0; mcb->sector = 0; mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long); mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry); /* mcb->chain[0].memadr = (long)&geometry; */ if (hdimcb(dk)) { printf("hd%d: can't read default geometry.\n", dk->dk_unit); return(1); } geo = &geometry.geometry_block; if (geo->version > 64000 || geo->version < 0) { printf("hd%d: bad default geometry version#.\n", dk->dk_unit); return(1); } if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) { printf("hd%d: bad default geometry header.\n", dk->dk_unit); return(1); } GB_CHECKSUM(geo, cnt); if (geometry.checksum != cnt) { printf("hd%d: bad default geometry checksum.\n", dk->dk_unit); return(1); } lp = &dk->dk_label; /* 1K block in Harris geometry; convert to sectors for disklabels */ for (cnt = 0; cnt < GB_MAXPART; cnt++) { lp->d_partitions[cnt].p_offset = geo->partition[cnt].start * (1024 / lp->d_secsize); lp->d_partitions[cnt].p_size = geo->partition[cnt].length * (1024 / lp->d_secsize); } lp->d_npartitions = GB_MAXPART; return(0);}#endif /* COMPAT_42 */#endif /* NHD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -